<?php
/**
 * File UserController.php
 *
 * @author Tuan Duong <bacduong@gmail.com>
 * @package Laravue
 * @version 1.0
 */

namespace App\Http\Controllers;

use App\Http\Resources\PermissionResource;
use App\Http\Resources\ReviewResource;
use App\Http\Resources\UserResource;
use App\Http\Resources\UserQuotationResource;
use App\Laravue\JsonResponse;
use App\Laravue\Models\Permission;
use App\Laravue\Models\Role;
use App\Laravue\Models\User;
use App\Product;
use App\ProductReview;
use App\UserQuotation;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Validator;

/**
 * Class UserController
 *
 * @package App\Http\Controllers
 */
class UserController extends Controller
{
    const ITEM_PER_PAGE = 20;

    /**
     * Display a listing of the user resource.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response|ResourceCollection
     */
    public function index(Request $request)
    {
        $searchParams = $request->all();
        $userQuery = User::query();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $role = Arr::get($searchParams, 'role', '');
        $keyword = Arr::get($searchParams, 'keyword', '');

        if ($role != "" && $role != null) {
            $userQuery->whereHas('roles', function ($q) use ($role) {
                $q->where('name', $role);
            });
        }

        if ($keyword != "" && $keyword != null) {
            $userQuery->where(function ($query) use ($keyword) {
                $query->where('name', 'LIKE', '%' . $keyword . '%')
                    ->orWhere('email', 'LIKE', '%' . $keyword . '%');
            });
        }

        return UserResource::collection($userQuery->paginate($limit));
    }

    public function assigned(Request $request)
    {
        $searchParams = $request->all();
        $userQuery = User::query();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);

        return UserResource::collection($userQuery->paginate($limit));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make(
            $request->all(),
            array_merge(
                $this->getValidationRules(),
                [
                    'password'        => [ 'required', 'min:6' ],
                    'confirmPassword' => 'same:password',
                ]
            )
        );

        if ($validator->fails()) {
            return response()->json([ 'errors' => $validator->errors() ], 403);
        } else {
            $params = $request->all();

            $fullName = $params['name'];
            if (isset($params['first_name'])) $fullName = $params['first_name'] . " ";
            if (isset($params['last_name'])) $fullName .= $params['last_name'];

            $furiganaName = $params['name'];
            if (isset($params['furigana_first_name'])) $furiganaName = $params['furigana_first_name'] . " ";
            if (isset($params['furigana_last_name'])) $furiganaName .= $params['furigana_last_name'];

            $user = User::create([
                'username'               => isset($params['username']) ? str_replace(" ", "", $params['username']) : str_replace(" ", "", $params['name']),
                'password'               => Hash::make($params['password']),
                'email'                  => $params['email'],
                'mobile_email'           => isset($params['mobile_email']) ? $params['mobile_email'] : null,
                'point'                  => (isset($params['point']) && $params['point'] != null) ? $params['point'] : 0,
                'registration_status'    => isset($params['registration_status']) ? $params['registration_status'] : 0,
                'usage_status'           => isset($params['usage_status']) ? $params['usage_status'] : 0,
                'membership_status'      => isset($params['membership_status']) ? $params['membership_status'] : 0,
                'membership_status_from' => isset($params['membership_status_from']) ? $params['membership_status_from'] : null,
                'membership_status_to'   => isset($params['membership_status_to']) ? $params['membership_status_to'] : null,
                'first_name'             => isset($params['first_name']) ? $params['first_name'] : $params['name'],
                'last_name'              => isset($params['last_name']) ? $params['last_name'] : $params['name'],
                'full_name'              => $fullName,
                'furigana_first_name'    => isset($params['furigana_first_name']) ? $params['furigana_first_name'] : $params['name'],
                'furigana_last_name'     => isset($params['furigana_last_name']) ? $params['furigana_last_name'] : $params['name'],
                'furigana_name'          => $furiganaName,
                'name'                   => str_replace(" ", "", $params['name']),
                'slug'                   => isset($params['username']) ? str_replace(" ", "", $params['username']) : str_replace(" ", "", $params['name']),
                'post_code'              => isset($params['post_code']) ? $params['post_code'] : null,
                'city'                   => isset($params['city']) ? $params['city'] : null,
                'district'               => isset($params['district']) ? $params['district'] : null,
                'address'                => isset($params['address']) ? $params['address'] : null,
                'phone_number'           => isset($params['phone_number']) ? $params['phone_number'] : null,
                'phone_number2'          => isset($params['phone_number2']) ? $params['phone_number2'] : null,
                'fax'                    => isset($params['fax']) ? $params['fax'] : null,
                'company'                => isset($params['company']) ? $params['company'] : null,
                'construction'           => (isset($params['construction']) && count($params['construction']) > 0) ? implode("_", $params['construction']) : null,
                'construction_2'         => isset($params['construction_2']) ? $params['construction_2'] : null,
                'paid_membership'        => (isset($params['paid_membership']) && ($params['paid_membership'] == 1 || $params['paid_membership'] == true)) ? 1 : 0,
                'introduction'           => isset($params['introduction']) ? $params['introduction'] : null,
                'group_id'               => (isset($params['group_id']) && $params['group_id'] != null) ? $params['group_id'] : 1,
                'login_url'              => $params['login_url'],
                'created_by'             => auth('api')->user()->id,
            ]);
            $role = Role::findByName($params['role']);
            $user->syncRoles($role);

            return new UserResource($user);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param User $user
     * @return UserResource|\Illuminate\Http\JsonResponse
     */
    public function show(User $user)
    {
        $editUser = User::findOrFail($user->id);
        return new UserResource($editUser);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param Request $request
     * @param User $user
     * @return UserResource|\Illuminate\Http\JsonResponse
     */
    public function update(Request $request, User $user)
    {
        if ($user === null) {
            return response()->json([ 'error' => 'User not found' ], 404);
        }

        $currentUser = Auth::user();
        if ($currentUser->id != 1 && $user->isAdmin()) {
            return response()->json([ 'error' => 'Admin can not be modified' ], 403);
        }

        /*$currentUser = Auth::user();
        if (!$currentUser->isAdmin() && $currentUser->id !== $user->id
            && !$currentUser->hasPermission(\App\Laravue\Acl::PERMISSION_USER_MANAGE)
            && !$currentUser->hasPermission(\App\Laravue\Acl::PERMISSION_USER_EDIT_MANAGE)
        ) {
            return response()->json(['error' => 'Permission denied'], 403);
        }*/

        $validator = Validator::make($request->all(), $this->getValidationRules(false));
        if ($validator->fails()) {
            return response()->json([ 'errors' => $validator->errors() ], 403);
        } else {
            $params = $request->all();

            $foundEmail = User::where('email', $params['email'])->first();
            if ($foundEmail && $foundEmail->id !== $user->id) {
                return response()->json([ 'error' => 'Email has been taken' ], 403);
            }

            $username = $user->username;
            if (isset($params['username'])) {
                $username = str_replace(" ", "", $params['username']);
                $foundUsername = User::where('username', $username)->first();
                if ($foundUsername && $foundUsername->id !== $user->id) {
                    return response()->json([ 'error' => 'Username has been taken' ], 403);
                }
            }

            $fullName = $user->full_name;
            if (isset($params['first_name'])) $fullName = $params['first_name'] . " ";
            if (isset($params['last_name'])) $fullName .= $params['last_name'];

            $furiganaName = $user->furigana_name;
            if (isset($params['furigana_first_name'])) $furiganaName = $params['furigana_first_name'] . " ";
            if (isset($params['furigana_last_name'])) $furiganaName .= $params['furigana_last_name'];

            $paidMembership = $user->paid_membership;
            if (isset($params['paid_membership'])) {
                $paidMembership = ($params['paid_membership'] == 1 || $params['paid_membership'] == true) ? 1 : 0;
            }

            $updateData = [
                'username'               => $username,
                'email'                  => isset($params['email']) ? $params['email'] : $user->email,
                'mobile_email'           => isset($params['mobile_email']) ? $params['mobile_email'] : $user->mobile_email,
                'point'                  => isset($params['point']) ? $params['point'] : $user->point,
                'registration_status'    => isset($params['registration_status']) ? $params['registration_status'] : $user->registration_status,
                'usage_status'           => isset($params['usage_status']) ? $params['usage_status'] : $user->usage_status,
                'membership_status'      => isset($params['membership_status']) ? $params['membership_status'] : $user->membership_status,
                'membership_status_from' => isset($params['membership_status_from']) ? $params['membership_status_from'] : $user->membership_status_from,
                'membership_status_to'   => isset($params['membership_status_to']) ? $params['membership_status_to'] : $user->membership_status_to,
                'first_name'             => isset($params['first_name']) ? $params['first_name'] : $user->first_name,
                'last_name'              => isset($params['last_name']) ? $params['last_name'] : $user->last_name,
                'full_name'              => $fullName,
                'furigana_first_name'    => isset($params['furigana_first_name']) ? $params['furigana_first_name'] : $user->furigana_first_name,
                'furigana_last_name'     => isset($params['furigana_last_name']) ? $params['furigana_last_name'] : $user->furigana_last_name,
                'furigana_name'          => $furiganaName,
                'name'                   => str_replace(" ", "", $params['name']),
                'slug'                   => isset($params['username']) ? str_replace(" ", "", $params['username']) : $user->slug,
                'post_code'              => isset($params['post_code']) ? $params['post_code'] : $user->post_code,
                'city'                   => isset($params['city']) ? $params['city'] : $user->city,
                'district'               => isset($params['district']) ? $params['district'] : $user->district,
                'address'                => isset($params['address']) ? $params['address'] : $user->address,
                'phone_number'           => isset($params['phone_number']) ? $params['phone_number'] : $user->phone_number,
                'phone_number2'          => isset($params['phone_number2']) ? $params['phone_number2'] : $user->phone_number2,
                'fax'                    => isset($params['fax']) ? $params['fax'] : $user->fax,
                'company'                => isset($params['company']) ? $params['company'] : $user->company,
                'construction'           => (isset($params['construction']) && count($params['construction']) > 0) ? implode("_", $params['construction']) : $user->construction,
                'construction_2'         => isset($params['construction_2']) ? $params['construction_2'] : $user->construction_2,
                'paid_membership'        => $paidMembership,
                'introduction'           => isset($params['introduction']) ? $params['introduction'] : $user->introduction,
                'group_id'               => isset($params['group_id']) ? $params['group_id'] : $user->group_id,
                'login_url'              => $params['login_url'],
                'updated_at'             => date('Y-m-d H:i:s')
            ];

            /*if (!$user->isAdmin()) {
                $updateData['group_id'] = isset($params['group_id']) ? $params['group_id'] : $user->group_id;
            }*/

            if ($request->has('password') && trim($request->get('password')) != "" && trim($request->get('password')) != null) {
                $updateData['password'] = Hash::make($request->get('password'));
            }

            $user->update($updateData);

            $role = Role::findByName($request->get('role'));
            if (isset($role)) {
                $user->syncRoles($role);
                $user->save();
            }

            return new UserResource($user);
        }
    }

    public function updateProfile(Request $request, User $user)
    {
        if ($user === null || ($user !== null && auth('api')->user()->id !== $user->id)) {
            return response()->json([ 'error' => 'User not found' ], 404);
        }

        $rules = [
            'username'            => [ 'required' ],
            'email'               => [ 'required', 'email' ],
            'first_name'          => [ 'required' ],
            'last_name'           => [ 'required' ],
            'furigana_first_name' => [ 'required' ],
            'furigana_last_name'  => [ 'required' ],
            'name'                => [ 'required' ],
            'post_code'           => [ 'required' ],
            'address'             => [ 'required' ],
            'address2'            => [ 'required' ],
            'address3'            => [ 'required' ],
            'phone_number'        => [ 'required' ],
        ];

        if ($request->get('password') != null && $request->get('password') != '') {
            $rules['password'] = [ 'required', 'min:8', 'max:12' ];
            $rules['confirmPassword'] = [ 'same:password' ];
        }

        if ($request->get('mobile_email') != null && $request->get('mobile_email') != '') {
            $rules['mobile_email'] = [ 'required', 'email' ];
        }

        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);
        $params = $request->all();

        $checkEmail = User::where('email', $params['email'])->where('id', '!=', $user->id)->count();
        if ($checkEmail > 0) return response()->json([ 'errors' => 'メールは既に存在します。' ], 403);

        if ($params['mobile_email'] !== null && $params['mobile_email'] !== '') {
            $checkMobileEmail = User::where('mobile_email', $params['mobile_email'])->where('id', '!=', $user->id)->count();
            if ($checkMobileEmail > 0) return response()->json([ 'errors' => '携帯mailは既に存在します。' ], 403);
        }

        $checkName = User::where('name', $params['name'])->where('id', '!=', $user->id)->count();
        if ($checkName > 0) return response()->json([ 'errors' => 'ニックネームは既に存在します。' ], 403);

        $updateData = [
            'mobile_email'        => $params['mobile_email'],
            'first_name'          => $params['first_name'],
            'last_name'           => $params['last_name'],
            'full_name'           => $params['first_name'] . ' ' . $params['last_name'],
            'furigana_first_name' => $params['furigana_first_name'],
            'furigana_last_name'  => $params['furigana_last_name'],
            'furigana_name'       => $params['furigana_first_name'] . $params['furigana_last_name'],
            'name'                => $params['name'],
            'post_code'           => $params['post_code'],
            'city'                => $params['address'],
            'district'            => $params['address2'],
            'address'             => $params['address3'],
            'phone_number'        => $params['phone_number'],
            'phone_number2'       => $params['phone_number2'],
            'fax'                 => $params['fax'],
            'company'             => $params['company'],
            'introduction'        => $params['introduction'],
            'updated_at'          => date('Y-m-d H:i:s'),
        ];

        if ($params['password'] != "") $updateData['password'] = Hash::make($params['password']);
		
		if ($user->isAdmin()) {
			$currentUser = Auth::user();
			if (!$currentUser->isAdmin() || $currentUser->id != 1) {
				return response()->json([ 'error' => 'Admin can not be modified' ], 403);
			}
		} else {
			$updateData['email'] = $params['email'];
		}
		
        $user->update($updateData);

        return response()->json([ 'status' => 'success', 'message' => 'Updated successfully.' ], 200);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param Request $request
     * @param User $user
     * @return UserResource|\Illuminate\Http\JsonResponse
     */
    public function updatePermissions(Request $request, User $user)
    {
        if ($user === null) {
            return response()->json([ 'error' => 'User not found' ], 404);
        }

        if ($user->isAdmin()) {
            return response()->json([ 'error' => 'Admin can not be modified' ], 403);
        }

        $permissionIds = $request->get('permissions', []);
        $rolePermissionIds = array_map(
            function ($permission) {
                return $permission['id'];
            },

            $user->getPermissionsViaRoles()->toArray()
        );

        $newPermissionIds = array_diff($permissionIds, $rolePermissionIds);
        $permissions = Permission::allowed()->whereIn('id', $newPermissionIds)->get();
        $user->syncPermissions($permissions);
        return new UserResource($user);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param User $user
     * @return \Illuminate\Http\Response
     */
    public function destroy(User $user)
    {
        if ($user->isAdmin()) {
            return response()->json([ 'error' => 'Ehhh! Can not delete admin user' ], 403);
        }

        try {
            $user->delete();
        } catch (\Exception $ex) {
            return response()->json([ 'error' => $ex->getMessage() ], 403);
        }

        return response()->json(null, 204);
    }

    /**
     * Get permissions from role
     *
     * @param User $user
     * @return array|\Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function permissions(User $user)
    {
        try {
            return new JsonResponse([
                'user' => PermissionResource::collection($user->getDirectPermissions()),
                'role' => PermissionResource::collection($user->getPermissionsViaRoles()),
            ]);
        } catch (\Exception $ex) {
            response()->json([ 'error' => $ex->getMessage() ], 403);
        }
    }

    /**
     * storeReview a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function storeReview(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'product_id' => [ 'required' ],
            'rate'       => [ 'required' ],
            'comment'    => [ 'required' ],
        ]);

        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);
        $params = $request->all();

        $product = Product::where('is_deleted', false)->where('id', $params['product_id'])->first();
        if (!$product) return response()->json([ 'error' => 'この商品は存在しません。' ], 403);
        $parentId = 0;

        if (isset($params['parent_id']) && $params['parent_id'] != null && $params['parent_id'] != '' && $params['parent_id'] != 0) {
            $checkParent = ProductReview::isPublished()->where('id', $params['parent_id'])->first();
            if ($checkParent) $parentId = $checkParent->id;
        }

        $comment = ProductReview::create([
            'product_id'   => $product->id,
            'parent_id'    => $parentId,
            'user_id'      => auth('api')->user()->id,
            'rate'         => $params['rate'],
            'comment'      => $params['comment'],
            'is_activated' => true,
            'created_at'   => date('Y-m-d H:i:s'),
            'updated_at'   => date('Y-m-d H:i:s')
        ]);

        return new ReviewResource($comment);
    }

    /**
     * storeReplyReview a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function storeReplyReview(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'parent_id' => [ 'required' ],
            'comment'   => [ 'required' ],
        ]);

        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);

        $params = $request->all();
        if ($params['parent_id'] == 0) return response()->json([ 'errors' => 'Data is invalid.' ], 403);

        $checkParent = ProductReview::where('is_deleted', false)->where('id', $params['parent_id'])->first();
        if (!$checkParent) return response()->json([ 'errors' => 'Data is invalid.' ], 403);

        $comment = ProductReview::create([
            'product_id'   => $checkParent->product_id,
            'parent_id'    => $checkParent->id,
            'user_id'      => auth('api')->user()->id,
            'rate'         => 0,
            'comment'      => $params['comment'],
            'is_activated' => true,
            'created_at'   => date('Y-m-d H:i:s'),
            'updated_at'   => date('Y-m-d H:i:s')
        ]);

        return new ReviewResource($comment);
    }

    /**
     * storeHiddenReview a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function storeHiddenReview(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id'     => [ 'required' ],
            'action' => [ 'required' ],
        ]);

        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);

        $params = $request->all();
        $checkParent = ProductReview::where('id', $params['id'])->first();
        if (!$checkParent) return response()->json([ 'errors' => 'Data is invalid.' ], 403);

        if ($params['action'] == 'delete') {
            $checkParent->update([ 'is_deleted' => true ]);
        } else {
            if ($checkParent->is_activated == true || $checkParent->is_activated == 1) {
                $checkParent->update([ 'is_activated' => false ]);
            } else {
                $checkParent->update([ 'is_activated' => true ]);
            }
        }

        return response()->json(null, 204);
    }

    public function estimateSaved(Request $request)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $keyword = Arr::get($searchParams, 'keyword', '');

        $user = auth('api')->user();
        $list = UserQuotation::where('user_id', $user->id);

        if (!empty($keyword)) {
            $list->where('code', 'LIKE', '%' . $keyword . '%')
                ->orWhere('product_name', 'LIKE', '%' . $keyword . '%');
        }
        $list->orderBy('id', 'DESC');

        return UserQuotationResource::collection($list->paginate($limit));
    }

    public function estimateDestroy($id = 0)
    {
        $user = auth('api')->user();
        $quotation = UserQuotation::where('user_id', $user->id)
            ->where('id', $id)
            ->first();
        if (!isset($quotation)) response()->json([ 'error' => 'Can not delete this quotation.' ], 403);

        try {
            $quotation->delete();
        } catch (\Exception $ex) {
            response()->json([ 'error' => $ex->getMessage() ], 403);
        }

        return response()->json(null, 204);
    }

    /**
     * @param bool $isNew
     * @return array
     */
    private function getValidationRules($isNew = true)
    {
        return [
            'name'  => 'required',
            'email' => $isNew ? 'required|email|unique:users' : 'required|email',
            'roles' => [
                'required',
                'array'
            ],
        ];
    }
}
