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

namespace App\Http\Controllers;

use App\Events\UserOnlineStatusEvent;
use App\Http\Resources\PermissionResource;
use App\Http\Resources\ProductResource;
use App\Http\Resources\UserChatResource;
use App\Http\Resources\UserResource;
use App\Jobs\GenerateUserAvatar;
use App\Laravue\JsonResponse;
use App\Laravue\Models\Permission;
use App\Laravue\Models\Role;
use App\Laravue\Models\User;
use App\Product;
use App\UserProject;
use App\UserProjectMember;
use App\UserWishlist;
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;
	private $_limitedItems;
	
	public function __construct()
	{
		$user = auth('api')->user();
		$this->_limitedItems = ['hasLimited' => false, 'data' => []];
		if ($user != null && !$user->hasRole('admin') && !$user->hasRole('manager') && !$user->hasPermissionTo('manage-user')) {
			$this->_limitedItems['hasLimited'] = true;
			$this->_limitedItems['data'] = User::select('id')->where('created_by', $user->id)->pluck('id')->toArray();
			if ($this->_limitedItems['data'] == null || count($this->_limitedItems['data']) <= 0) {
				$this->_limitedItems['data'][] = 0;
			}
		}
	}
	
	/**
	 * 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', '');
		$isLeader = Arr::get($searchParams, 'isLeader', '');
		$ignoreId = Arr::get($searchParams, 'ignoreId', '');
		$keyword = Arr::get($searchParams, 'keyword', '');
		
		if ($role != "" && $role != null) {
			$userQuery->whereHas('roles', function ($q) use ($role) {
				$q->where('name', $role);
			});
		}
		
		if ($isLeader != "") {
			if ($isLeader == 0 || $isLeader == "0" || $isLeader == 1 || $isLeader == "1") {
				$userQuery->where('is_leader', $isLeader);
			}
		}
		
		if ($ignoreId != "") {
			$userQuery->where('id', '!=', $ignoreId);
		}
		
		if ($keyword != "" && $keyword != null) {
			$userQuery->where(function ($query) use ($keyword) {
				$query->where('name', 'LIKE', '%' . $keyword . '%')
					->orWhere('email', 'LIKE', '%' . $keyword . '%');
			});
		}
		
		if ($this->_limitedItems['hasLimited']) {
			$userQuery->whereIn('id', $this->_limitedItems['data']);
		}
		
		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);
		
		if ($this->_limitedItems['hasLimited']) {
			$userQuery->whereIn('id', $this->_limitedItems['data']);
		}
		
		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'];
			
			$userData = [
				'username'            => $params['email'],
				'password'            => Hash::make($params['password']),
				'email'               => $params['email'],
				'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'                => 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,
				'introduction'        => isset($params['introduction']) ? $params['introduction'] : null,
				'login_url'           => isset($params['login_url']) ? $params['login_url'] : "/",
				'created_by'          => auth('api')->user()->id,
				'created_at'          => date('Y-m-d H:i:s')
			];
			
			if (isset($params['is_allowed_record_single'])) $userData['is_allowed_record_single'] = ($params['is_allowed_record_single'] === true) ? 1 : 0;
			if (isset($params['is_allowed_report_single'])) $userData['is_allowed_report_single'] = ($params['is_allowed_report_single'] === true) ? 1 : 0;
			if (isset($params['time_allowed_record'])) $userData['time_allowed_record'] = $params['time_allowed_record'] . ':00';
			
			if (isset($params['is_leader'])) {
				$userData['is_leader'] = ($params['is_leader'] === true) ? 1 : 0;
				if (isset($params['is_allowed_record_group'])) $userData['is_allowed_record_group'] = ($params['is_allowed_record_group'] === true) ? 1 : 0;
				if (isset($params['is_allowed_report_group'])) $userData['is_allowed_report_group'] = ($params['is_allowed_report_group'] === true) ? 1 : 0;
			}
			
			$user = User::create($userData);
			$role = Role::findByName($params['role']);
			$user->syncRoles($role);
			
			if (isset($params['members'])) {
				foreach ($params['members'] as $item) {
					$userProject = UserProject::create([
						'user_id'    => $user->id,
						'project_id' => $item['project_id'],
						'created_at' => date('Y-m-d H:i:s'),
						'updated_at' => date('Y-m-d H:i:s'),
					]);
					
					if (isset($item['users'])) {
						foreach ($item['users'] as $uItem) {
							UserProjectMember::create([
								'user_project_id' => $userProject->id,
								'user_id'         => $uItem[0],
								'created_at'      => date('Y-m-d H:i:s'),
								'updated_at'      => date('Y-m-d H:i:s'),
							]);
						}
					}
				}
			}
			
			GenerateUserAvatar::dispatch($user)->onQueue(config('queue.connections.redis.queue'));
			
			return new UserResource($user);
		}
	}
	
	/**
	 * Display the specified resource.
	 *
	 * @param User $user
	 * @return UserResource|\Illuminate\Http\JsonResponse
	 */
	public function show(User $user)
	{
		if ($this->_limitedItems['hasLimited']) {
			$userCheck = User::select('id')->where('id', $user->id)->whereIn('id', $this->_limitedItems['data'])->first();
			if ($userCheck === null || !isset($userCheck->id)) {
				return response()->json(['error' => 'User not found'], 404);
			}
		}
		
		return new UserResource($user);
	}
	
	/**
	 * 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 ($this->_limitedItems['hasLimited']) {
			$userCheck = User::select('id')->where('id', $user->id)->whereIn('id', $this->_limitedItems['data'])->first();
			if ($userCheck === null || !isset($userCheck->id)) {
				return response()->json(['error' => 'User not found'], 404);
			}
		}
		
		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)
		) {
			echo "<pre>";print_r('okoko');echo "</pre>";die();
			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);
			}
			
			$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'];
			
			$updateData = [
				'username'            => isset($params['email']) ? $params['email'] : $user->email,
				'email'               => isset($params['email']) ? $params['email'] : $user->email,
				'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'                => str_replace(" ", "", $params['name']),
				'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,
				'introduction'        => isset($params['introduction']) ? $params['introduction'] : $user->introduction,
				'login_url'           => isset($params['login_url']) ? $params['login_url'] : $user->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'));
			}
			
			if (isset($params['is_allowed_record_single'])) $updateData['is_allowed_record_single'] = ($params['is_allowed_record_single'] === true) ? 1 : 0;
			if (isset($params['is_allowed_report_single'])) $updateData['is_allowed_report_single'] = ($params['is_allowed_report_single'] === true) ? 1 : 0;
			if (isset($params['time_allowed_record'])) $updateData['time_allowed_record'] = $params['time_allowed_record'] . ':00';
			
			if (isset($params['is_leader'])) {
				$updateData['is_leader'] = ($params['is_leader'] === true) ? 1 : 0;
				if (isset($params['is_allowed_record_group'])) $updateData['is_allowed_record_group'] = ($params['is_allowed_record_group'] === true) ? 1 : 0;
				if (isset($params['is_allowed_report_group'])) $updateData['is_allowed_report_group'] = ($params['is_allowed_report_group'] === true) ? 1 : 0;
			}
			
			$user->update($updateData);
			$role = Role::findByName($request->get('role'));
			if (isset($role)) {
				$user->syncRoles($role);
				$user->save();
			}
			
			if (isset($params['members'])) {
				$listIds = UserProject::where('user_id', $user->id)->pluck('id')->toArray();
				UserProjectMember::whereIn('user_project_id', $listIds)->delete();
				UserProject::where('user_id', $user->id)->delete();
				foreach ($params['members'] as $item) {
					$userProject = UserProject::create([
						'user_id'    => $user->id,
						'project_id' => $item['project_id'],
						'created_at' => date('Y-m-d H:i:s'),
						'updated_at' => date('Y-m-d H:i:s'),
					]);
					if (isset($item['users'])) {
						foreach ($item['users'] as $uItem) {
							UserProjectMember::create([
								'user_project_id' => $userProject->id,
								'user_id'         => $uItem[0],
								'created_at'      => date('Y-m-d H:i:s'),
								'updated_at'      => date('Y-m-d H:i:s'),
							]);
						}
					}
				}
			}
			
			return new UserResource($user);
		}
	}
	
	public function updateProfile(Request $request, User $user)
	{
		$rules = [
			'full_name'     => ['required', 'string', 'max:255'],
			'furigana_name' => ['required', 'string', 'max:255'],
			'gender'        => ['required'],
			'date_of_birth' => ['required'],
		];
		
		$validator = Validator::make($request->all(), $rules);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		$avatar = (isset($params['avatar']) && $params['avatar'] != null && $params['avatar'] != "") ? $params['avatar'] : 'avatar.png';
		
		$user->update([
			'full_name'     => $params['full_name'],
			'furigana_name' => $params['furigana_name'],
			'gender'        => (isset($params['gender']) && $params['gender'] == 1) ? 1 : 0,
			'date_of_birth' => $params['date_of_birth'],
			'avatar'        => $avatar,
			'updated_at'    => date('Y-m-d H:i:s')
		]);
		
		return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
	}
	
	public function updateEmail(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), [
			'email'        => ['required', 'email', 'max:255'],
			'phone_number' => ['required', 'string', 'max:15'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		
		$user->update([
			'email'        => $params['email'],
			'phone_number' => $params['phone_number'],
			'mobile_tel'   => $params['mobile_tel'],
			'updated_at'   => date('Y-m-d H:i:s')
		]);
		
		return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
	}
	
	public function updatePassword(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), [
			'current_password' => ['required', 'string', 'min:6', 'max:30'],
			'password'         => ['required', 'string', 'min:6', 'max:30'],
			'confirm_password' => ['same:password'],
			'reminder'         => ['required'],
			'reminder_answer'  => ['required', 'string', 'max:255'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		if (!Hash::check($params['current_password'], $user->password)) return response()->json(['status' => 'error', 'message' => 'The current password is incorrect.'], 200);
		$user->fill([
			'password'          => Hash::make($params['password']),
			'reminder_question' => $params['reminder'],
			'reminder_answer'   => $params['reminder_answer'],
			'updated_at'        => date('Y-m-d H:i:s')
		])->save();
		
		return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
	}
	
	public function updateCertification(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), [
			'image' => ['required'],
			'type'  => ['required', 'numeric', 'max:2'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		$updateData = [];
		if ($params['image'] != null && $params['image'] != "") {
			if ($params['type'] == 0) {
				$updateData['driver_license'] = $params['image'];
			} else if ($params['type'] == 1) {
				$updateData['insurance_card'] = $params['image'];
			} else {
				$updateData['number_card'] = $params['image'];
			}
		}
		
		if (count($updateData) > 0) {
			$updateData['updated_at'] = date('Y-m-d H:i:s');
			$user->update($updateData);
			
			return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
		}
		
		return response()->json(['status' => 'error', 'message' => 'Data is invalid.'], 200);
	}
	
	public function updateAddress(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), [
			'post_code' => ['required', 'string', 'max:255'],
			'city'      => ['required', 'string', 'max:255'],
			'district'  => ['required', 'string', 'max:255'],
			'address'   => ['required', 'string', 'max:255'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		$user->update([
			'post_code'  => $params['post_code'],
			'city'       => $params['city'],
			'district'   => $params['district'],
			'address'    => $params['address'],
			'address2'   => $params['address2'],
			'updated_at' => date('Y-m-d H:i:s')
		]);
		
		return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
	}
	
	public function updateShippingAddress(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), [
			'shipping_post_code' => ['required', 'string', 'max:255'],
			'shipping_city'      => ['required', 'string', 'max:255'],
			'shipping_district'  => ['required', 'string', 'max:255'],
			'shipping_address'   => ['required', 'string', 'max:255'],
		]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || ($user->id != auth('api')->user()->id)) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$params = $request->all();
		$user->update([
			'shipping_post_code'  => $params['shipping_post_code'],
			'shipping_city'       => $params['shipping_city'],
			'shipping_district'   => $params['shipping_district'],
			'shipping_address'    => $params['shipping_address'],
			'shipping_address2'   => $params['shipping_address2'],
			'shipping_updated_at' => date('Y-m-d H:i:s')
		]);
		
		return response()->json(['status' => 'success', 'message' => 'Updated successfully.'], 200);
	}
	
	public function updateProfileFull(Request $request, User $user)
	{
		if ($user === null) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$rules = [
			'first_name'          => ['required', 'string', 'max:255'],
			'last_name'           => ['required', 'string', 'max:255'],
			'furigana_first_name' => ['required', 'string', 'max:255'],
			'furigana_last_name'  => ['required', 'string', 'max:255'],
			'post_code'           => ['required', 'min:1', 'max:10'],
			'address'             => ['required', 'string', 'max:255'],
			'address2'            => ['required', 'string', 'max:255'],
			'phone_number'        => ['required', 'min:8', 'max:15'],
			'email'               => ['required', 'email'],
			'password'            => ['required', 'string', 'min:6', 'max:30'],
			'confirm_password'    => ['same:password'],
			'gender'              => ['required'],
			'dob_year'            => ['required'],
			'dob_month'           => ['required'],
			'dob_day'             => ['required'],
			'reminder'            => ['required', 'string', 'max:2'],
			'reminder_answer'     => ['required', 'string', 'max:255'],
			'mail_subscribe'      => ['required'],
			'mail_format'         => ['required'],
		];
		
		/*if ($request->get('password') != null && $request->get('password') != '') {
			$rules['password'] = [ 'required', 'string', 'min:6', 'max:30' ];
			$rules['confirm_password'] = ['same:password'];
		}*/
		
		$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(['data' => ['status' => 'error', 'name' => 'email_exist', 'message' => 'メールは既に存在します。']], 200);
		
		$updateData = [
			'password'            => Hash::make($params['password']),
			'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'],
			'post_code'           => $params['post_code'],
			'city'                => $params['address'],
			'address'             => $params['address2'],
			'address2'            => isset($params['address3']) ? $params['address3'] : '',
			'phone_number'        => $params['phone_number'],
			'fax_number'          => $params['fax_number'],
			'career'              => $params['career'],
			'mobile_tel'          => (isset($params['mobile_tel']) && !empty($params['mobile_tel'])) ? $params['mobile_tel'] : null,
			'emg_tel'             => (isset($params['emg_tel']) && !empty($params['emg_tel'])) ? $params['emg_tel'] : null,
			'gender'              => (isset($params['gender']) && $params['gender'] == 0) ? 0 : 1,
			'date_of_birth'       => $params['dob_year'] . '-' . $params['dob_month'] . '-' . $params['dob_day'],
			'reminder_question'   => $params['reminder'],
			'reminder_answer'     => $params['reminder_answer'],
			'email2'              => $params['email2'],
			'email_subscribe'     => $params['mail_subscribe'],
			'email_format'        => $params['mail_format'],
			'updated_at'          => date('Y-m-d H:i:s')
		];
		
		//if ($params['password'] != "") $user->password = Hash::make($params['password']);
		
		if (!$user->isAdmin()) {
			//return response()->json(['error' => 'Admin can not be modified'], 403);
			$updateData['email'] = $params['email'];
		}
		$user->update($updateData);
		
		return response()->json(['data' => ['status' => 'success', 'message' => 'Updated successfully.']], 200);
	}
	
	public function wishlist(Request $request, User $user)
	{
		if ($user === null || $user->id !== auth('api')->user()->id) {
			return response()->json(['error' => 'User not found'], 404);
		}
		
		$searchParams = $request->all();
		$limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
		$listIds = UserWishlist::where('user_id', auth('api')->user()->id)->pluck('product_id')->toArray();
		$list = Product::isPublished()->whereIn('id', $listIds)->orderBy('id', 'DESC');
		
		return ProductResource::collection($list->paginate($limit));
	}
	
	public function wishlistStore(Request $request, User $user)
	{
		$validator = Validator::make($request->all(), ['id' => ['required']]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		
		if ($user === null || $user->id !== auth('api')->user()->id) {
			return response()->json(['status' => 'error', 'message' => 'User not found'], 200);
		}
		
		$params = $request->all();
		$product = Product::isPublished()->where('id', $params['id'])->first();
		if (!$product) {
			return response()->json(['status' => 'error', 'message' => 'Product not found'], 200);
		}
		
		$countItem = UserWishlist::where('user_id', auth('api')->user()->id)->where('product_id', $product->id)->count();
		if ($countItem <= 0) {
			UserWishlist::create([
				'user_id'    => auth('api')->user()->id,
				'product_id' => $product->id,
				'created_at' => date('Y-m-d H:i:s'),
				'updated_at' => date('Y-m-d H:i:s')
			]);
		}
		
		return response()->json(['status' => 'success', 'message' => 'Add product to wish list successfully.'], 200);
	}
	
	public function wishlistDestroy(User $user, Product $product)
	{
		if ($user === null || $user->id !== auth('api')->user()->id) {
			return response()->json(['status' => 'error', 'message' => 'User not found'], 200);
		}
		
		if ($product === null) {
			return response()->json(['status' => 'error', 'message' => 'Product not found'], 200);
		}
		
		UserWishlist::where('user_id', auth('api')->user()->id)->where('product_id', $product->id)->delete();
		
		return response()->json(['status' => 'success', 'message' => "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);
	}
	
	public function updateOnlineStatus(Request $request)
	{
		$user = auth('api')->user();
		$status = $request->status;
		$user->update(['is_online' => $status === 'online', 'last_activity' => now()]);
		broadcast(new UserOnlineStatusEvent($user, $status))->toOthers();
		
		return response()->json(['status' => 'success'], 200);
	}
	
	/**
	 * Remove the specified resource from storage.
	 *
	 * @param User $user
	 * @return \Illuminate\Http\Response
	 */
	public function destroy(User $user)
	{
		if ($user->isAdmin()) {
			response()->json(['error' => 'Ehhh! Can not delete admin user'], 403);
		}
		
		try {
			$user->delete();
		} catch (\Exception $ex) {
			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);
		}
	}
	
	public function chatList(Request $request)
	{
		$searchParams = $request->all();
		$limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
		$role = Arr::get($searchParams, 'role', '');
		$keyword = Arr::get($searchParams, 'keyword', '');
		$userQuery = User::select('id', 'name', 'full_name', 'username', 'avatar', 'is_online', 'last_activity')
			->where('is_deleted', 0)
			->where('is_activated', 1)
			->where('id', '!=', auth('api')->user()->id);
		
		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 . '%')
					->orWhere('username', 'LIKE', '%' . $keyword . '%')
					->orWhere('full_name', 'LIKE', '%' . $keyword . '%');
			});
		}
		
		$userQuery->orderBy('is_online', 'DESC')->orderBy('last_activity', 'DESC');
		
		return UserChatResource::collection($userQuery->paginate($limit));
	}
	
	public function storeFcmToken(Request $request)
	{
		$validator = Validator::make($request->all(), ['fcm_token' => ['required']]);
		if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
		$user = Auth::user(); //$user = auth('api')->user();
		$user->fcm_token = $request->fcm_token;
		$user->save();
		return response()->json(['message' => 'FCM token saved successfully']);
	}
	
	/**
	 * Store PWA push subscription
	 */
	public function storePwaSubscription(Request $request)
	{
		$validator = Validator::make($request->all(), [
			'subscription'             => ['required', 'array'],
			'subscription.endpoint'    => ['required', 'string'],
			'subscription.keys'        => ['required', 'array'],
			'subscription.keys.p256dh' => ['required', 'string'],
			'subscription.keys.auth'   => ['required', 'string'],
		]);
		
		if ($validator->fails()) {
			return response()->json(['errors' => $validator->errors()], 403);
		}
		
		$user = Auth::user();
		$subscription = $request->input('subscription');
		
		// Store subscription data
		$user->pwa_endpoint = $subscription['endpoint'];
		$user->pwa_p256dh = $subscription['keys']['p256dh'];
		$user->pwa_auth = $subscription['keys']['auth'];
		$user->pwa_user_agent = $request->input('user_agent');
		$user->pwa_platform = $request->input('platform');
		$user->push_notifications_enabled = true;
		$user->save();
		
		return response()->json([
			'message'         => 'PWA subscription stored successfully',
			'subscription_id' => $user->id
		]);
	}
	
	/**
	 * Remove PWA push subscription
	 */
	public function removePwaSubscription(Request $request)
	{
		$user = Auth::user();
		
		// Clear subscription data
		$user->pwa_endpoint = null;
		$user->pwa_p256dh = null;
		$user->pwa_auth = null;
		$user->pwa_user_agent = null;
		$user->pwa_platform = null;
		$user->push_notifications_enabled = false;
		$user->save();
		
		return response()->json(['message' => 'PWA subscription removed successfully']);
	}
	
	/**
	 * Get PWA notification preferences
	 */
	public function getPwaNotificationPreferences()
	{
		$user = Auth::user();
		return response()->json([
			'push_notifications_enabled' => $user->push_notifications_enabled,
			'has_pwa_subscription'       => !empty($user->pwa_endpoint)
		]);
	}
	
	/**
	 * Update PWA notification preferences
	 */
	public function updatePwaNotificationPreferences(Request $request)
	{
		$validator = Validator::make($request->all(), [
			'push_notifications_enabled' => ['required', 'boolean']
		]);
		
		if ($validator->fails()) {
			return response()->json(['errors' => $validator->errors()], 403);
		}
		
		$user = Auth::user();
		$user->push_notifications_enabled = $request->push_notifications_enabled;
		$user->save();
		
		return response()->json([
			'message'                    => 'PWA notification preferences updated successfully',
			'push_notifications_enabled' => $user->push_notifications_enabled
		]);
	}
	
	/**
	 * Get PWA VAPID public key
	 */
	public function getPwaPublicKey()
	{
		return response()->json([
			'public_key' => config('services.pwa.public_key')
		]);
	}
	
	/**
	 * Update user chat status for anti-spam notifications
	 */
	public function updateChatStatus(Request $request)
	{
		$user = Auth::user();
		if (!$user) {
			return response()->json(['error' => 'Unauthorized'], 401);
		}
		
		$conversationId = $request->input('conversation_id');
		$pageVisible = $request->input('page_visible', false);
		$lastActivity = $request->input('last_activity', time());
		
		// Store user activity in cache for 5 minutes
		$cacheKey = "user_chat_active_{$user->id}";
		$cacheData = [
			'conversation_id' => $conversationId,
			'page_visible'    => $pageVisible,
			'last_activity'   => $lastActivity
		];
		
		cache()->put($cacheKey, $cacheData, 300); // 5 minutes
		
		return response()->json(['message' => 'Chat status updated']);
	}
	
	/**
	 * Get attendance statistics for all users or specific user based on plan data
	 *
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function getAttendanceStatistics(Request $request)
	{
		// Check permissions
		$currentUser = Auth::user();
		if (!$currentUser || (!$currentUser->hasRole('admin') && !$currentUser->hasRole('manager') && !$currentUser->hasPermissionTo('manage-user'))) {
			return response()->json(['error' => 'Permission denied'], 403);
		}
		
		$searchParams = $request->all();
		$userId = Arr::get($searchParams, 'user_id', null);
		$dateFrom = Arr::get($searchParams, 'date_from', null);
		$dateTo = Arr::get($searchParams, 'date_to', null);
		
		// Get all users first to ensure we show everyone, even if they have no plan data
		$usersQuery = User::select('id', 'full_name', 'name')
			->where('is_deleted', 0)
			->where('is_activated', 1);
		
		if ($userId) {
			$usersQuery->where('id', $userId);
		}
		
		$users = $usersQuery->get();
		
		// Initialize user stats for all users
		$userStats = [];
		foreach ($users as $user) {
			$userStats[$user->id] = [
				'user_id'            => $user->id,
				'user_name'          => $user->full_name ?: $user->name,
				'day_shift_hours'    => 0,    // Changed to hours
				'night_shift_hours'  => 0,    // Changed to hours
				'processing_hours'   => 0,    // Changed to hours
				'survey_hours'       => 0,    // Changed to hours
				'meeting_hours'      => 0,    // Changed to hours
				'conference_hours'   => 0,    // Changed to hours
				'training_hours'     => 0,    // Changed to hours
				'overtime_hours'     => 0,    // Already hours
				'travel_hours'       => 0,    // Changed to hours
				'year_end_hours'     => 0,    // Changed to hours
				'holiday_work_hours' => 0,    // Changed to hours
				'total_work_days'    => 0     // Will be calculated from total hours / 8
			];
		}
		
		// Get plan details with user assignments in the date range
		$planDetails = \App\PlanDetail::query()
			->join('plans', 'plan_details.plan_id', '=', 'plans.id')
			->join('plan_detail_users', 'plan_details.id', '=', 'plan_detail_users.plan_detail_id')
			->select([
				'plan_detail_users.user_id',
				'plans.plan_date',
				'plan_details.type',
				'plan_details.time_start',
				'plan_details.time_end',
				'plan_details.time_range'
			])
			->where('plans.is_deleted', 0)
			->where('plans.is_activated', 1);
		
		// Apply date filter only if both dates are provided
		if ($dateFrom && $dateTo) {
			$planDetails->whereBetween('plans.plan_date', [$dateFrom, $dateTo]);
		}
		
		if ($userId) {
			$planDetails->where('plan_detail_users.user_id', $userId);
		}
		
		$planDetails = $planDetails->get();
		
		// Process plan details and calculate statistics
		foreach ($planDetails as $detail) {
			$userId = $detail->user_id;
			
			if (!isset($userStats[$userId])) {
				continue; // Skip if user not in our list
			}
			
			// Calculate working hours for this detail
			$workingHours = 0;
			if ($detail->type == 7) {
				// Type 7 (残業): Use time_range directly
				$workingHours = $detail->time_range ? floatval($detail->time_range) : 0;
			} else {
				// Other types: Calculate from time_start to time_end
				if ($detail->time_start && $detail->time_end) {
					try {
						// Parse datetime strings and extract time for calculation
						$startTime = \Carbon\Carbon::parse($detail->time_start);
						$endTime = \Carbon\Carbon::parse($detail->time_end);
						
						if ($startTime && $endTime) {
							// Handle case where end time is next day (e.g., night shift)
							// Compare only the time parts
							$startTimeOfDay = $startTime->format('H:i:s');
							$endTimeOfDay = $endTime->format('H:i:s');
							
							if ($endTimeOfDay < $startTimeOfDay) {
								$endTime->addDay();
							}
							
							$workingHours = $endTime->diffInMinutes($startTime) / 60.0; // Convert to hours
						}
					} catch (\Exception $e) {
						// Log error but continue processing
						\Log::warning("Failed to parse time for plan detail", [
							'time_start' => $detail->time_start,
							'time_end'   => $detail->time_end,
							'error'      => $e->getMessage()
						]);
						$workingHours = 0;
					}
				}
			}
			
			// Add working hours to appropriate category based on type (0-10)
			switch ($detail->type) {
				case 0: // 通常勤務（日勤）
					$userStats[$userId]['day_shift_hours'] += $workingHours;
					break;
				case 1: // 通常勤務（夜勤）
					$userStats[$userId]['night_shift_hours'] += $workingHours;
					break;
				case 2: // 加工
					$userStats[$userId]['processing_hours'] += $workingHours;
					break;
				case 3: // 現場調査（現調）
					$userStats[$userId]['survey_hours'] += $workingHours;
					break;
				case 4: // 打ち合わせ
					$userStats[$userId]['meeting_hours'] += $workingHours;
					break;
				case 5: // 会議
					$userStats[$userId]['conference_hours'] += $workingHours;
					break;
				case 6: // 講習
					$userStats[$userId]['training_hours'] += $workingHours;
					break;
				case 7: // 残業
					$userStats[$userId]['overtime_hours'] += $workingHours;
					break;
				case 8: // 出張
					$userStats[$userId]['travel_hours'] += $workingHours;
					break;
				case 9: // 年末年始
					$userStats[$userId]['year_end_hours'] += $workingHours;
					break;
				case 10: // 休日出勤
					$userStats[$userId]['holiday_work_hours'] += $workingHours;
					break;
			}
		}
		
		// Calculate total work days for each user (total hours / 8)
		foreach ($userStats as $userId => $stats) {
			$totalHours = $stats['day_shift_hours'] + $stats['night_shift_hours'] +
				$stats['processing_hours'] + $stats['survey_hours'] +
				$stats['meeting_hours'] + $stats['conference_hours'] +
				$stats['training_hours'] + $stats['overtime_hours'] +
				$stats['travel_hours'] + $stats['year_end_hours'] +
				$stats['holiday_work_hours'];
			
			$userStats[$userId]['total_work_days'] = round($totalHours / 8, 1);
		}
		
		// Convert to array and sort by user name
		$result = array_values($userStats);
		usort($result, function ($a, $b) {
			return strcmp($a['user_name'], $b['user_name']);
		});
		
		// Get all users for dropdown (regardless of filter)
		$allUsers = User::select('id', 'full_name', 'name')
			->where('is_deleted', 0)
			->where('is_activated', 1)
			->orderBy('full_name')
			->get();
		
		return response()->json([
			'data'        => $result,
			'date_range'  => [
				'from' => $dateFrom,
				'to'   => $dateTo
			],
			'total_users' => count($result),
			'all_users'   => $allUsers
		]);
	}
	
	/**
	 * Export attendance statistics to CSV based on plan data
	 *
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function exportAttendanceStatistics(Request $request)
	{
		// Check permissions
		$currentUser = Auth::user();
		if (!$currentUser || (!$currentUser->hasRole('admin') && !$currentUser->hasRole('manager') && !$currentUser->hasPermissionTo('manage-user'))) {
			return response()->json(['error' => 'Permission denied'], 403);
		}
		
		$searchParams = $request->all();
		$userId = Arr::get($searchParams, 'user_id', null);
		$dateFrom = Arr::get($searchParams, 'date_from', null);
		$dateTo = Arr::get($searchParams, 'date_to', null);
		
		// Get statistics data
		$request->merge(['user_id' => $userId, 'date_from' => $dateFrom, 'date_to' => $dateTo]);
		$statisticsResponse = $this->getAttendanceStatistics($request);
		$statisticsData = json_decode($statisticsResponse->getContent(), true);
		
		if (!isset($statisticsData['data'])) {
			return response()->json(['error' => 'No data found'], 404);
		}
		
		$data = $statisticsData['data'];
		
		// Create CSV content
		$csvData = [];
		
		// CSV Headers (Japanese) - Enhanced to include all work types
		$csvData[] = [
			'ユーザーID',
			'ユーザー名',
			'通常勤務（日勤）',
			'通常勤務（夜勤）',
			'加工',
			'現場調査（現調）',
			'打ち合わせ',
			'会議',
			'講習',
			'残業',
			'出張',
			'年末年始',
			'休日出勤',
			'総作業日数'
		];
		
		// Add user data
		foreach ($data as $userStat) {
			$csvData[] = [
				$userStat['user_id'],
				$userStat['user_name'],
				number_format($userStat['day_shift_hours'], 1),
				number_format($userStat['night_shift_hours'], 1),
				number_format($userStat['processing_hours'], 1),
				number_format($userStat['survey_hours'], 1),
				number_format($userStat['meeting_hours'], 1),
				number_format($userStat['conference_hours'], 1),
				number_format($userStat['training_hours'], 1),
				number_format($userStat['overtime_hours'], 1),
				number_format($userStat['travel_hours'], 1),
				number_format($userStat['year_end_hours'], 1),
				number_format($userStat['holiday_work_hours'], 1),
				number_format($userStat['total_work_days'], 1)
			];
		}
		
		// Generate filename with current date and range
		$filename = 'work_statistics_' . date('YmdHis') . '.csv';
		
		// Create exports directory if it doesn't exist
		$exportsPath = public_path('exports');
		if (!file_exists($exportsPath)) {
			mkdir($exportsPath, 0755, true);
		}
		
		// Write CSV file to public/exports directory
		$filePath = $exportsPath . '/' . $filename;
		$handle = fopen($filePath, 'w');
		
		// Add BOM for proper UTF-8 encoding in Excel
		fprintf($handle, chr(0xEF) . chr(0xBB) . chr(0xBF));
		
		foreach ($csvData as $row) {
			fputcsv($handle, $row);
		}
		
		fclose($handle);
		
		// Return file download URL
		$downloadUrl = url('exports/' . $filename);
		
		return response()->json([
			'success'      => true,
			'download_url' => $downloadUrl,
			'filename'     => $filename
		]);
	}
	
	/**
	 * Get all active users for dropdown
	 *
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function getAllActiveUsers()
	{
		$users = User::select('id', 'full_name', 'name')
			->where('is_deleted', 0)
			->where('is_activated', 1)
			->orderBy('full_name')
			->get();
		
		return response()->json([
			'data' => $users
		]);
	}
	
	/**
	 * @param bool $isNew
	 * @return array
	 */
	private function getValidationRules($isNew = true)
	{
		return [
			'name'  => 'required',
			'email' => $isNew ? 'required|email|unique:users' : 'required|email',
			'roles' => [
				'required',
				'array'
			],
		];
	}
}
