<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\Controller;
use App\Models\Approver;
use App\Models\Employee;
use App\Models\EmployeeLeave;
use App\Models\EmployeeLeaveCredits;
use App\Models\LeaveLedger;
use App\Models\LeaveType;
use App\Models\NotificationErrorLog;
use App\Models\User;
use App\Notifications\Leave;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
use Throwable;

class LeaveApprovalController extends Controller
{
    public function index(Request $request)
    {
        $employee = Auth::user();

        DB::enableQueryLog();

        $keyword = $request->input('keyword', '');
        $perPage = $request->input('per_page', PHP_INT_MAX);
        $sortBy = $request->input('sortBy', 'pending');
        $sortType = $request->input('sortType', 'desc');

        $currentEmp = $employee->employees ? $employee->employees->employee_id : '';
        
        $approverHierarchy = Approver::where('approvers', 'like', '%"'.$employee->employee_id.'"%')->get()
                ->groupBy('type')->map(fn($group) => $group->pluck('type_id')->toArray());

        // $firstIteration = true;
        // foreach ($approverHierarchy as $type => $ids) {
        //     $column = $type === 'dealership' ? 'dealer_id' : $type . '_id';
        //     echo $column;
            
        //     if ($firstIteration) {
        //         // $query->whereIn('employees.' . $column, $ids);
        //         $firstIteration = false;
        //     } else {
        //         // $query->orWhereIn('employees.' . $column, $ids);
        //     }
        // }

        // dd($approverHierarchy);

        DB::enableQueryLog();

        $classification_id = $employee->employees->classification_id;

        $data = EmployeeLeave::with(['recommending', 'approving', 'employee', 'leave_type'])
            ->join('employees', 'employee_leaves.employee_id', '=', 'employees.employee_id')

            ->where(function ($query) use ($employee) {
                $employeeId = optional($employee->employees)->employee_id;
                if ($employeeId) {
                    $query->where('recommending_id', $employeeId)
                        ->orWhere('approver_id', $employeeId);
                }
            })

            // ->orWhere(function ($query) use ($approverHierarchy) { 
            //     foreach ($approverHierarchy as $type => $ids) {
            //         $column = $type === 'dealership'
            //             ? 'employees.dealer_id'
            //             : "employees.{$type}_id";

            //         $query->orWhereIn($column, $ids);
            //     }
            // })

            ->where('employee_leaves.enabled', 1)
            ->whereNull('employee_leaves.deleted_at') 

            ->select(
                'employees.*',
                'employee_leaves.*',
                'employee_leaves.created_at as leave_created_at'
            )

            ->selectRaw(
                '(SELECT COUNT(*)
                    FROM employee_leaves AS el
                    WHERE el.deleted_at IS NULL              
                    AND el.status IN (0, 1)
                    AND (el.recommending_id = ? OR el.approver_id = ?)
                ) AS pending,

                (SELECT COUNT(*)
                    FROM employee_leaves AS el
                    WHERE el.deleted_at IS NULL              
                    AND el.status = 2
                    AND (el.recommending_id = ? OR el.approver_id = ?)
                ) AS approved,

                (SELECT COUNT(*)
                    FROM employee_leaves AS el
                    WHERE el.deleted_at IS NULL             
                    AND el.status = 99
                    AND (el.recommending_id = ? OR el.approver_id = ?)
                ) AS denied',
                [$currentEmp, $currentEmp, $currentEmp, $currentEmp, $currentEmp, $currentEmp]
            );
            // ->where('status', '!=', 99)
            // ->where('status', '!=', 2)
            // ->where('validated', '!=', 1)
            // ->get();
        
        if ($request->date_created) {
            $dates = explode(' to ', $request->date_created); // Split into start and end date
            if (count($dates) == 2) {
                $data = $data->whereBetween('created_at', [$dates[0], $dates[1]]);
            }
        }

        if ($request->range) {
            $dates = explode(' to ', $request->range); // Split into start and end date
            if (count($dates) == 2) {
                $data = $data->whereBetween('date_from', [$dates[0], $dates[1]]);
            }
        } 
        
        if ($request->status && is_array($request->status)) {
            $data = $data->where(function ($query) use ($request) {
                if (in_array('pending', $request->status)) {
                    $query->orWhere(function ($q) {
                        $q->where('status', 0)->orWhere('status', 1);
                    });
                }
                
                if (in_array('validated', $request->status)) {
                    $query->orWhere(function ($q) {
                        $q->where('status', 2)->where('validated', 1);
                    });
                }
                
                if (in_array('denied', $request->status)) {
                    $query->orWhere(function ($q) {
                        $q->where('status', 99)
                            ->orWhere(function ($q2) {
                                $q2->where('status', 2)->where('validated', 99);
                            });
                    });
                }
                
                if (in_array('for_validation', $request->status)) {
                    $query->orWhere(function ($q) {
                        $q->where('status', 2)->where('validated', 0);
                    });
                }
            });
        } else {
            $data = $data->where('status', '!=', 99)
                ->where('status', '!=', 2)
                ->where('validated', '!=', 1);
        }

        $data = $data->orderBy('leave_created_at', 'DESC')->get();
        
        // dd($request->all());

        $mailAction = array();

        if($request->action && $request->leave_id_url){
            $mailAction['action'] = $request->action;
            $mailAction['leave_id_url'] = Crypt::decrypt($request->leave_id_url);

            $data = $data->where('id', $mailAction['leave_id_url'])->first();
            
        }

        return response()->json(['data' => $data, 'mailAction' => $mailAction]);
    }

    public function update(Request $request, int $id)
    {
        $data = EmployeeLeave::with(['employee', 'leave_type'])->find($id);

        if (!$data) {
            return response()->json(['messages' => 'No data found.'], 404);
        }
    
        if($request->status == 99){
            if($data->without_pay != 1){
                $leave_credits = EmployeeLeaveCredits::where([
                    'employee_id' => $data->employee_id,
                    'enabled' => 1,
                    'leave_type_id' => $data->leave_id  
                ])->first();
                
                $remaining_leave = $leave_credits->remaining + $data->days;
                $remaining_hours = $leave_credits->hours + ($data->days * 8);
                
                try {
                    DB::connection()->beginTransaction();

                    $leave_credits->remaining = $remaining_leave;
                    $leave_credits->hours = $remaining_hours;
                    
                    $leave_credits->save();

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

                } catch(Throwable $e) {
                    DB::rollBack();
                    return response()->json([
                        'status' => false,
                        'message' => 'Unable to process request. Please try again.',
                        'data' => $e->getMessage()
                    ], Response::HTTP_INTERNAL_SERVER_ERROR);
                }
            }
        }

        DB::beginTransaction();

        try {
            $now = date('Y-m-d H:i:s');

            if ($request->status == 2) {
                $request['approved_at'] = $now;
            } elseif ($request->status == 1) {
                $request['recommended_at'] = $now;
            }

            if ($data->fill($request->all())->save()) {
                $data->touch();

                $employee_id_for_notification = $request->status == 1 ? $data->approver_id : $data->employee_id;
                // Fetch and validate email before sending

                $employee = Employee::find($employee_id_for_notification);
                if ($employee && filter_var($employee->email, FILTER_VALIDATE_EMAIL)) {
                    $this->sendNotification($employee_id_for_notification, $data);
                }

                if ($request->status == 2) {
                    try {
                        $leaveName = LeaveType::where('id', $data->leave_id)->pluck('name')->first();

                        $ledger = [
                            'employee_id' => $data->employee_id,
                            'company_id' => $data->company_id,
                            'dealer_id' => $data->dealer_id,
                            'leave_id' => $data->id,
                            'date_from' => $data->date_from,
                            'date_to' => $data->date_to,
                            'credits_from' => $data->credits_from,
                            'credits_to' => $data->credits_to,
                            'credit' => $data->without_pay == 1 ? '0' : $data->days,
                            'hours' => $data->without_pay == 1 ? '0' : $data->hours,
                            'leave_type' => $data->leave_id,
                            'leave_name' => $leaveName . ($data->credit_to_vl == 1 ? ' - Credited to VL' : ''),
                            'date_applied' => date('Y-m-d'),
                        ];

                        

                        LeaveLedger::create($ledger);
                    } catch(Throwable $e) {
                        DB::rollback();
                        return response()->json([
                            'status'  => false,
                            'message' => 'Unable to process request. Please try again.',
                            'data'    => $e->getMessage()
                        ]);
                    } 
                }

                DB::commit();

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

            } else {
                DB::rollback();
                return response()->json([
                    'status' => false,
                    'message' => 'Unable to save employee leave data.'
                ], 500);
            }

        } catch (Throwable $e) {
            DB::rollback();
            return response()->json([
                'status'  => false,
                'message' => 'Unable to process request. Please try again.',
                'data'    => $e->getMessage()
            ]);
        }
    }


    public function updateApprover(Request $request, int $id)
    {
        $data = EmployeeLeave::with(['employee', 'leave_type'])->find($id);

        if (!$data) {
            return response()->json(['messages' => 'No data found.'], 404);
        }

        DB::beginTransaction();

        try {
            $employee_ids_for_notification = array_filter([
                $request->recommending_id != $data->recommending_id ? $request->recommending_id : null,
                $request->approver_id != $data->approver_id ? $request->approver_id : null,
            ]);

            foreach ($employee_ids_for_notification as $employee_id) {
                $this->sendNotification($employee_id, $data);
            }

            $data->fill($request->all())->save();
            $data->touch();

            DB::commit();

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

        } catch (Throwable $e) {
            DB::rollback();
            return response()->json([
                'status'  => false,
                'message' => 'Unable to process request. Please try again.',
                'data'    => $e->getMessage()
            ]);
        }
    }

    public function HrValidation(Request $request,int $id){
       
        $status = $request->status;
        $data = EmployeeLeave::with('employee','leave_type')->find($id);
        if(!$data){
            return response()->json(['messages' => 'No data found.']);
        }
        $employee_id  =Auth::user()->employees->employee_id;
        
        DB::beginTransaction();
        try{
            $data->validated_by = $employee_id;
            $data->validated_at = now();
            $data->validated = $status;
            $data->denied_reason = $request->reason;

            // try {
            //     $this->sendNotification($data->employee_id, $data);
            // } catch (Throwable $e) {
            //     // Log the notification error but continue processing
            //     $this->logNotificationError('Failed to send HR validation notification: ' . $e->getMessage());
            // }
            
            $data->save();
            // $data->touch();
            // $email_to = $this->getEmployeeEmailData($data->employee_id);
            
            DB::commit();
            return response()->json([
                'message' => 'Record Successfully updated!',
                'status' => 'success',
                'data' => $data,
            ], 201);
        } catch (Throwable $e) {
            DB::rollback();
            return response()->json([
                'status'  => false,
                'message' => 'Unable to process request. Please try again.',
                'data'    => $e->getMessage()
            ]);
        }
        
    }

    public function sendNotification($employee_id, $data)
    {
        $email_to = $this->getEmployeeEmailData($employee_id);
   
        if ($email_to) {
            Notification::send($email_to, new Leave($data));
        } else {
            $this->logNotificationError('Email To Not Found');
        }
    }

    private function logNotificationError($message)
    {
        try {
            NotificationErrorLog::create([
                'user_id' => Auth::id(),
                'model' => 'App\Model\EmployeeLeave',
                'message' => $message
            ]);
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
        }
    }

    public function getEmployeeEmailData($id)
    {
        return User::where('employee_id', $id)->first();
    }
}
