<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\Controller;
use App\Mail\ForgotPasswordMail;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;
use App\Models\User;
use App\Models\UserRole;
use App\Models\DepartmentAccess;
use DateTime;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class UserController extends Controller
{
    public function index(Request $request)
    {
        $keyword = $request->input('keyword', ''); /**search keyword */
        $perPage = $request->input('per_page',PHP_INT_MAX); /**items per page, default all records for dropdown purpose */
        $sortBy = $request->input('sortBy', null); /**sorting by field */
        $sortType = $request->input('sortType', 'ASC'); /**sort type */
        $keyword = str_replace(' ','%', $keyword); /**search keyword */

        /**Fetch records */
        $data = User::where(function ($q) use ($keyword) {
            $q->where('first_name', 'like', '%' . $keyword . '%')
            ->orWhere('last_name', 'like', '%' . $keyword . '%')
            ->orWhere('name', 'like', '%' . $keyword . '%')
            ->orWhere('username', 'like', '%' . $keyword . '%')
            ->orWhere('email', 'like', '%' . $keyword . '%')
            ->orWhere('employee_id', 'like', '%' . $keyword . '%')
            ->orWhereHas('roles', fn($qr) => $qr->where('name', 'like', '%' . $keyword . '%'));
        })->whereNull('deleted_at');

        /**If sorting */
        if ($sortBy) {
            $data = $data->orderBy($sortBy, $sortType);
        }
        /**paginate */
        $data = $data->paginate($perPage);
        /**send response */
        return response()->json($data, 200);
    }

    /**
     * Display the specified resource.
     */
    public function show(string $user_id)
    {
        $department_access = DepartmentAccess::find($user_id);

        $dept_ids = [];

        foreach($department_access as $departmentaccess){
            $dept_ids[] = $departmentaccess;
        }

        /**Find user by id */
        $user = User::find($user_id);

        if($user) { /**If record found, send response with record */
            return response()->json([
                'data'    => $user,
            ], 200);
        }
        /**otherwise send response with no record found*/
        return response()->json(['status'  => false, 'messages' => 'No data found.'], 202);
    }

    public function login(Request $request)
    {
        $request->validate([
            'username' => 'required',
            'password' => 'required',
        ]);

        /**validate token */
        $token = Auth::attempt($request->only('username', 'password'));
        /** If invalid, response unauthorized */
        if (!$token) {
            return response()->json([
                'message' => 'Unauthorized',
            ], 401);
        }
        /**if valid fetch record */
        $user = Auth::user();
        /**response with record */
        return response()->json([
            'user' => $user,
            'token' => $token,
        ],200);
    }

    /**Saving record */
    public function store(Request $request)
    {
        $user = User::where('employee_id','=',$request->employee_id)->orWhere('asa_id','=',$request->employee_id)->first();
        if(!$user) return response()->json([
            'message' => 'Employee do not have ASA account yet.',
        ], 422);

        // Validate the incoming request data
        $validator = Validator::make($request->all(), [
            'employee_id' => 'required',
            'roles' => 'required',
        ]);

        if ($validator->fails()) { /**If validation failed, response with error messages */
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], 422);
        }

        /**If passed validation, begin the transaction */

        DB::connection()->beginTransaction();

        try {

            /**Save User role/s */
            foreach($request->roles as $role) {
                UserRole::updateOrCreate(
                    [
                        'user_id' => $user->id,
                        'role_id' => $role,
                    ],
                    [
                        'user_id' => $user->id,
                        'role_id' => $role,
                    ],
                );
            }

            /**Commit the transactions */
            DB::connection()->commit();

            /**Response with success message */
            return response()->json([
                'message' => 'Record Successfully added!',
            ], 201);

        } catch (\Throwable $e) {
            /**If something wrong happens, rollback the transactios */
            DB::connection()->rollback();
            /**Response with error message */
            return response()->json([
                'message' => 'Unable to process request. Please try again.',
                'data'    => $e->getMessage()
            ], 422);
        }
    }

    public function update(Request $request, int $id)
    {
        /**Find the user by id */
        $data = User::find($id);

        /**If no record found, response with error message */
        if (!$data) {
            return response()->json(['messages' => 'No data found.'], 422);
        }

        /**If has record, begin the transaction */
        DB::connection()->beginTransaction();

        try {

            /**fill the updated data */
            $data->fill($request->all());
            /**Save updated data */
            $data->save();
            /**apply the update */
            $data->touch();

            /**find Role in UserRole */
            $userRole = UserRole::where('user_id', $id);
            /**then delete the current record */
            $userRole->delete();
            /**If has roles */
            if($request['roles']) {

                /**put all submitted roles into container*/
                $roles = [];
                foreach($request->roles as $role) {
                    $roles[] = array("user_id"=>$data->id, "role_id"=>$role, "created_at"=>$data->updated_at, "updated_at"=>$data->updated_at);
                }
                /**Insert roles */
                UserRole::insert($roles);
            }

            $deptAccess = DepartmentAccess::where('user_id', $data->id);
            $deptAccess->delete();

            $departments = [];
            if($request->departments) {
                foreach($request->departments as $department) {
                    $departments[] = [
                        'user_id' => $data->id,
                        'department_id' => $department,
                        'created_at' => $data->updated_at,
                        'updated_at' => $data->updated_at,
                    ];
                }
            }

            DepartmentAccess::insert($departments);
            /**Commit all transactions */
            DB::connection()->commit();

            /**response with update success */
            return response()->json([
                'message' => 'Record Successfully updated!',
                'data' => $data,
            ], 201);

        } catch (\Throwable $e) {
            /**If something wrong happens, rollback all transactions */
            DB::connection()->rollback();
            /**response with error message */
            return response()->json([
                'message' => 'Unable to process request. Please try again.',
                'data'    => $e->getMessage()
            ], 422);
        }
    }

    public function filtered(Request $request)
    {
        $system_id = $request->input('system_id', null);
        $group_id = $request->input('role_group_id', null);
        $company_id = $request->input('company_id', null);
        $dealer_id = $request->input('dealer_id', null);
        /**Fetch records */
        DB::enableQueryLog();
        $data = User::without(['roles', 'employees', 'department_access', 'employee_profile_picture']);
        if($system_id) {
            $data = $data->whereHas('roles', fn($q) => $q->whereHas('group', fn($q2) => $q2->where('system_id', $system_id)));
        }
        if($group_id) {
            $data = $data->whereHas('roles', fn($q) => $q->where('group_id', $group_id));
        }
        if($dealer_id) {
            $data = $data->whereHas('roles', fn($q) => $q->whereHas('company_access', fn($q2) => $q2->where('dealership_id', $dealer_id)));
        }
        if($company_id) {
            $data = $data->whereHas('roles', fn($q) => $q->whereHas('company_access', fn($q2) => $q2->where('company_id', $company_id)));
        }
        $data = $data->get();
        // dd(DB::getQueryLog());
        /**send response */
        return response()->json($data, 200);
    }
    
    function isPasswordExpired(Request $request) {
        // dd($request->all());

        $user = User::where('employee_id', $request->employee_id)->first();
        $passwordLastChanged = new DateTime($user->last_password_change);
        $passwordExpiryDays = 90; // Example: Password expires after 90 days
        $expiryDate = $passwordLastChanged->modify("+{$passwordExpiryDays} days");

        if($user->last_password_change == null) {
            $passwordExpired = 1; // Password expired
        } else {
            $passwordExpired = 0; // Password valid
        }
        
        return response()->json([
            'passwordExpired' => $passwordExpired
        ]);
    }

    public function forgotPassword(Request $request){
        // Validate the email
        $request->validate([
            'email' => 'required|email',
            'employee_id' => 'required'
        ]);

        // Find the employee
        $employee = DB::table('users')
            ->join('employees', 'users.employee_id', '=', 'employees.employee_id')
            ->where('users.email', $request->email)
            ->where('employees.employee_id', $request->employee_id)
            ->whereNull('employees.date_resign')
            ->first();

        // Check if employee exists
        if (!$employee) {
            return response()->json([
                'success' => false,
                'message' => 'Email/Employee ID does not match an active account.'
            ], 404);
        }

        // Generate random 7-character password (mix of letters and numbers)
        $newPassword = $this->generateRandomPassword(7);

        // Hash the password
        $hashedPassword = Hash::make($newPassword);

        // Update the password in database
        DB::table('users')
            ->join('employees', 'users.employee_id', '=', 'employees.employee_id')
            ->where('users.email', $request->email)
            ->whereNull('employees.date_resign')
            ->update([
                'users.password' => $hashedPassword,
                'users.updated_at' => now()
            ]);

        // Send email notification
        try {
            Mail::to($employee->email)->send(new ForgotPasswordMail($employee, $newPassword));
            
            return response()->json([
                'success' => true,
                'message' => 'A temporary password has been sent to your email address.'
            ], 200);
        } catch (\Exception $e) {
            // Log the error
            Log::error('Failed to send password reset email: ' . $e->getMessage());
            dd($e->getMessage());

            return response()->json([
                'success' => false,
                'message' => 'Password was reset but email could not be sent. Please contact support.'
            ], 500);
        }
    }

    /**
     * Generate random password with letters and numbers
     */
    private function generateRandomPassword($length = 7){
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $password = '';
        
        for ($i = 0; $i < $length; $i++) {
            $password .= $characters[rand(0, strlen($characters) - 1)];
        }
        
        return $password;
    }

    public function options(Request $request)
    {
        $perPage = (int) $request->input('per_page', 500);
        $perPage = max(1, min($perPage, 500));

        return User::select(['id','first_name','last_name','employee_id'])
            ->whereNull('deleted_at')
            ->orderBy('id')
            ->paginate($perPage);
    }
}
