<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\Controller;
use App\Models\Employee;
use App\Models\EmployeeLeave;
use App\Models\EmployeeLeaveCredits;
use App\Models\EmployeeOb;
use App\Models\EmployeeOffset;
use App\Models\EmployeeOffsetEarning;
use App\Models\EmployeeOvertime;
use App\Models\EmployeeTimeAdjustment;
use App\Models\EmployeeUndertime;
use App\Models\OffsetRemaining;
use App\Notifications\Leave;
use App\Notifications\OffsetAvailment;
use App\Notifications\OffsetEarning;
use App\Notifications\Overtime;
use App\Notifications\TimeAdjustment;
use App\Notifications\Travel;
use App\Notifications\Undertime;
use DateInterval;
use DatePeriod;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Throwable;

class AttendanceCreationMobileController extends Controller
{
    public function leave_request(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);

        if($request->leave_id != 1){
            $leave_credits = EmployeeLeaveCredits::where([
                'employee_id' => $user[0]->employee_id,
                'enabled' => 1,
                'leave_type_id' => $request->leave_id
            ])->first();
           
            if($request->days > 2 && strlen($request->attachment) == 0){
                return response()->json([
                    'status'  => false,
                    'message' => 'Medical certificate is required'
                ]);
            }

            $requestDataForGettingOfHours = new Request([
                'employee_id' => $user[0]->employee_id,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
            ]);

            
            $getHours = $this->getHoursForLeaveDependsOnSchedule($requestDataForGettingOfHours);

            $content = $getHours->getContent();  

            // dd($content);
            if($content == "false"){
                return response()->json([
                    'status'  => false,
                    'message' => 'Schedule is required'
                ]);
            }

            // Get the content of the JsonResponse
            $hours = $getHours->getContent();

            if($request->half_day == 1){
                $hours = $hours / 2;
            }

            $days = $hours / 8;

            $without_pay = 0;
            
            try {

                DB::connection()->beginTransaction();
                
                if($leave_credits){
                    if($days > $leave_credits->remaining && $leave_credits->remaining < 0.5){
                        $without_pay = 1;
                    }

                    if($days > $leave_credits->remaining && $leave_credits->remaining > 0.49){
                        return response()->json([
                            'status'  => false,
                            'message' => 'Days must not exceed the available credits',
                            'remaining' => $leave_credits->remaining
                        ]);
                    } else {
                        if($leave_credits->remaining > 0.49){
                            $remaining_leave = $leave_credits->remaining - $days;
                            $remaining_hours = $leave_credits->hours - $hours;
            
                            $updateData = [
                                'remaining' => $remaining_leave
                            ];
                    
                            $leave_credits->remaining = $remaining_leave;
                            $leave_credits->hours = $remaining_hours;

                            $leave_credits->save();
                        }
                    }
                } else {
                    $without_pay = 1;
                }
                
                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);
            }
        }

        $validator = Validator::make($request->all(), [
            'leave_id' => 'required',
            'half_day' => 'required',
            'date_from' => 'required|date',
            'date_to' => 'required|date',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => false,
                'message' => $validator->errors()->first(),
                'errors' => $validator->errors()
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        DB::beginTransaction();
        
        try {
            $attachmentOnLeave = new EmployeeLeaveController();

            $attachmentName = $attachmentOnLeave->handleAttachment($request);

            $status = EmployeeLeave::create([
                'leave_id' => $request->leave_id,
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'half_day' => $request->half_day,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
                'without_pay' => $without_pay,
                'days' => $days,
                'hours' => $hours,
                'description' => $request->description != 'null' ? $request->description : NULL,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

            DB::commit();

            $status->load(['employee', 'leave_type']);
            $emailTo = $attachmentOnLeave->getEmployeeEmailData($request->recommending_id);

            Notification::send($emailTo, new Leave($status));

            return response()->json([
                'status' => true,
                'message' => 'Saved successfully!',
            ], Response::HTTP_CREATED);

        } 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);
        }
    }

    public function overtime_request(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);

        $validator = Validator::make($request->all(), [
            'date_from' => "required|date",
            'date_to' => "required|date",
            'from_time' => "required",
            'to_time' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

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

        try {
            
            $fromTime = new DateTime($request->from_time);
            $toTime = new DateTime($request->to_time);

            $interval = $fromTime->diff($toTime);

            $totalMinutes = $interval->h * 60 + $interval->i;
            $decimalHours = $totalMinutes / 60;

            $attachmentOnOvertime = new EmployeeOvertimeController();

            $attachmentName = $attachmentOnOvertime->handleAttachment($request);

            $Status = EmployeeOvertime::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
                'from_time' => $request->from_time,
                'to_time' => $request->to_time,
                'hours' => $decimalHours,
                'charge_to' => $request->charge_to,
                'meal' => $request->meal,
                'transportation' => $request->transportation,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

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

            // Load the relationships
            $Status->load(['employee']);

            $email_to = $attachmentOnOvertime->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new Overtime($Status));

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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

    public function undertime_request(Request $request)
    {

        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);
        
        $validator = Validator::make($request->all(), [
            'date' => "required|date",
            'from_time' => "required",
            'to_time' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        try {
            $fromTime = new DateTime($request->from_time);
            $toTime = new DateTime($request->to_time);

            $interval = $fromTime->diff($toTime);

            $totalMinutes = $interval->h * 60 + $interval->i;
            $decimalHours = $totalMinutes / 60;

            $attachmentOnUndertime = new EmployeeUndertimeController();

            $attachmentName = $attachmentOnUndertime->handleAttachment($request);

            $Status = EmployeeUndertime::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date' => $request->date,
                'from_time' => $request->from_time,
                'to_time' => $request->to_time,
                'hours' => $decimalHours,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

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

            // Load the relationships
            $Status->load(['employee']);
            
            $email_to = $attachmentOnUndertime->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new Undertime($Status));

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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

    public function travel_request(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);
        
        $validator = Validator::make($request->all(), [
            'date_from' => "required",
            'date_to' => "required",
            'from_time' => "required",
            'to_time' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        DB::connection()->beginTransaction();
        
        try {
            $attachmentOnTravel = new EmployeeObController();

            $attachmentName = $attachmentOnTravel->handleAttachment($request);
            
            $Status = EmployeeOb::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
                'from_time' => $request->from_time,
                'to_time' => $request->to_time,
                'destination' => $request->destination,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

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

            // Load the relationships
            $Status->load(['employee']);

            $email_to = $attachmentOnTravel->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new Travel($Status));

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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

    public function offset_availment_request(Request $request)
    {

        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);

        $availableOffset = OffsetRemaining::where('employee_id', '=', $request->employee_id)
            ->pluck('remaining');
        
        $fromTime = new DateTime($request->from_time);
        $toTime = new DateTime($request->to_time);

        if($request->date_from != $request->date_to){
            $requestDataForGettingOfHours = new Request([
                'employee_id' => $user[0]->employee_id,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
            ]);

            $getHours = $this->getHoursForLeaveDependsOnSchedule($requestDataForGettingOfHours);

            $decimalHours = $getHours->getContent(); 

            if($decimalHours == "false"){
                return response()->json([
                    'status'  => false,
                    'message' => 'Schedule is required'
                ]);
            }
        } else {
            $interval = $fromTime->diff($toTime);

            $totalMinutes = $interval->h * 60 + $interval->i;
            $decimalHours = $totalMinutes / 60;
            $decimalHours = (float) $decimalHours;
        }

        if($decimalHours > $availableOffset[0]){
            return response()->json([
                'status'  => false,
                'message' => 'Hours must not exceed the available hours',
                'total_request_hours' => $decimalHours,
                'hours_remaining' => $availableOffset[0]
            ]);
        }
        
        // dd($request->all());

        $validator = Validator::make($request->all(), [
            'date_from' => "required",
            'date_to' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

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

        try {
            $attachmentOnOffsetAvailment = new EmployeeOffsetController();

            $attachmentName = $attachmentOnOffsetAvailment->handleAttachment($request);

            $Status = EmployeeOffset::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date_from' => $request->date_from,
                'date_to' => $request->date_to,
                'from_time' => $request->from_time,
                'to_time' => $request->to_time,
                'hours' => $decimalHours,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

            if(!OffsetRemaining::where('employee_id', '=', $Status->employee_id)->exists()){
                OffsetRemaining::create([
                    'employee_id' => $Status->employee_id,
                    'company_id' => $Status->company_id,
                    'remaining' => $decimalHours
                ]);
            } else {
                $offset = OffsetRemaining::where('employee_id', '=', $Status->employee_id)->first();

                if ($offset) {
                    $offset->decrement('remaining', $decimalHours);
                }
            }

            DB::connection()->commit();
            
            // Load the relationships
            $Status->load(['employee']);

            $email_to = $attachmentOnOffsetAvailment->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new OffsetAvailment($Status));
            
            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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

    public function offset_earning_request(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);
        
        $validator = Validator::make($request->all(), [
            'date' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

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

        try {
            $attachmentOnOffsetEarning = new EmployeeOffsetEarningController();

            $attachmentName = $attachmentOnOffsetEarning->handleAttachment($request);
            
            $fromTime = new DateTime($request->from_time);
            $toTime = new DateTime($request->to_time);

            $interval = $fromTime->diff($toTime);

            $totalMinutes = $interval->h * 60 + $interval->i;
            $decimalHours = $totalMinutes / 60;

            $Status = EmployeeOffsetEarning::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date' => $request->date,
                'from_time' => $request->from_time,
                'to_time' => $request->to_time,
                'hours' => $decimalHours,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

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

            // Load the relationships
            $Status->load(['employee']);

            $email_to = $attachmentOnOffsetEarning->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new OffsetEarning($Status));

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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

    private function getApprover($user, $request)
    {
        $mrfApprover = new ApproverController();

        if($user[0]->classification_id == 1){
            $approver_results = $mrfApprover->getRankAndFileApprover($user[0]->employee_id);
        } else if ($user[0]->classification_id == 2) {
            $approver_results = $mrfApprover->getSupervisorApprover($user[0]->employee_id);
        } else if ($user[0]->classification_id == 3) {
            $approver_results = $mrfApprover->getManagerApprover($user[0]->employee_id);
        }
        
        $approver_results['endorser'] = array_diff($approver_results['endorser'], ["LOREMIPSUM"]);

        // Flatten the endorser array
        $cleanedApproverArray = [];

        foreach ($approver_results['endorser'] as $item) {
            // Remove square brackets and quotes, then split the string by commas
            $ids = explode(',', str_replace(['[', ']', '"'], '', $item));
            $cleanedApproverArray = array_merge($cleanedApproverArray, $ids);
        }

        // Remove any duplicate IDs
        $cleanedApproverArray = array_unique($cleanedApproverArray);

        // Retrieve endorsers using the cleaned array
        $endorser = Employee::whereIn('employee_id', $cleanedApproverArray)->get();

        if($user[0]->classification_id == 1){
            foreach($endorser as $approver_result){
                if($approver_result->classification_id == 2 || $approver_result->classification_id == 1){
                    $request['recommending_id'] = $approver_result->employee_id;
                }
                if($request['recommending_id'] == ''){
                    if($approver_result->classification_id == 3){
                        $request['recommending_id'] = $approver_result->employee_id;
                    }
                }

                if($approver_result->classification_id == 3){
                    $request['approver_id'] = $approver_result->employee_id;
                }
                if($request['approver_id'] == ''){
                    if($approver_result->classification_id == 4){
                        $request['approver_id'] = $approver_result->employee_id;
                    }
                }
            }
        }

        if($user[0]->classification_id == 2){
            foreach($endorser as $approver_result){
                if($approver_result->classification_id == 2 || $approver_result->classification_id == 1){
                    $request['recommending_id'] = $approver_result->employee_id;
                }
                if($request['recommending_id'] == ''){
                    if($approver_result->classification_id == 3){
                        $request['recommending_id'] = $approver_result->employee_id;
                    }
                }

                if($approver_result->classification_id == 3){
                    $request['approver_id'] = $approver_result->employee_id;
                }
                if($request['approver_id'] == ''){
                    if($approver_result->classification_id == 4){
                        $request['approver_id'] = $approver_result->employee_id;
                    }
                }
            }
        }

        if($user[0]->classification_id == 3){
            foreach($endorser as $approver_result){

                if($approver_result->classification_id == 3){
                    $request['recommending_id'] = $approver_result->employee_id;
                    $request['approver_id'] = $approver_result->employee_id;
                }
                if($request['approver_id'] == ''){
                    if($approver_result->classification_id == 4){
                        $request['recommending_id'] = $approver_result->employee_id;
                        $request['approver_id'] = $approver_result->employee_id;
                    }
                }
            }
        }

        return $request;
    }

    public function getHoursForLeaveDependsOnSchedule(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();

        $scheduleController = new EmployeeAttendanceController();
        
        $start_date = new DateTime($request->date_from);
        $end_date = new DateTime($request->date_to);
        $end_date->modify('+1 day');

        $period = new DatePeriod($start_date, new DateInterval('P1D'), $end_date);
        
        $hoursTotal = 0;

        $length = iterator_count($period);
        $index = 0;
        
        foreach ($period as $date) {
            $formattedDate = $date->format('Y-m-d');

            $holiday = $scheduleController->getHoliday($formattedDate);
            $schedule = $scheduleController->getSchedule($formattedDate, $user[0]->employee_id);

            if(!$schedule){
                return response()->json(false);
            }

            $dayOfWeek = date('l', strtotime($formattedDate));
            if ($schedule) {
                $daysArray = explode(',', $schedule->schedule->day_off); // Convert string to array
            } else {
                $daysArray = []; // Or any default value
            }
            
            if(!$holiday && !in_array($dayOfWeek, $daysArray)){
                $daysCWSArray = explode(',', $schedule->schedule->cws_day);

                if(in_array($dayOfWeek, $daysCWSArray)){
                    $fromTime = new DateTime($schedule->schedule['cws_from_time']);
                    $toTime = new DateTime($schedule->schedule['cws_to_time']);
                } else {
                    $fromTime = new DateTime($schedule->schedule['from_time']);
                    $toTime = new DateTime($schedule->schedule['to_time']);
                }

                $interval = $fromTime->diff($toTime);

                $hours = $interval->h + ($interval->days * 24); // Calculate total hours

                $hoursMinusOne = $hours - 1;

                if($request->half_day == 1){
                    if($index == 0){
                        $hoursMinusOne = $hoursMinusOne / 2;
                    }
                } else if ($request->half_day == 2) {
                    if($index == $length - 1){
                        $hoursMinusOne = $hoursMinusOne / 2;
                    }
                }

                $hoursTotal += $hoursMinusOne;
            }

            $index++;
        }

        return response()->json($hoursTotal);
    }

    public function time_adjustment_request(Request $request)
    {
        $user = Employee::where('employee_id', $request->employee_id)->get();
        
        $request = $this->getApprover($user, $request);
        
        $validator = Validator::make($request->all(), [
            'date' => "required",
            'time' => "required",
        ]);

        /** If validation fails return with error message */
        if ($validator->fails()) {
            $errors = $validator->errors();
            $first = $errors->getMessages();
            return response()->json([
                'status'  => false,
                'message' => (reset($first))[0],
                'errors'  => $errors
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        DB::connection()->beginTransaction();
        
        try {
            $attachmentOnTimeAdjustment = new EmployeeTimeAdjustmentController();

            $attachmentName = $attachmentOnTimeAdjustment->handleAttachment($request);
            
            $Status = EmployeeTimeAdjustment::create([
                'employee_id' => $user[0]->employee_id,
                'company_id' => $user[0]->company_id,
                'dealer_id' => $user[0]->dealer_id,
                'date' => $request->date,
                'in_out' => $request->in_out,
                'time' => $request->time,
                'description' => $request->description,
                'attachment' => $attachmentName,
                'recommending_id' => $request->recommending_id,
                'approver_id' => $request->approver_id,
                'status' => 0,
            ]);

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

            // Load the relationships
            $Status->load(['employee']);

            $email_to = $attachmentOnTimeAdjustment->getEmployeeEmailData($request->recommending_id);

            Notification::send($email_to, new TimeAdjustment($Status));

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
            ],201);

        } catch (Throwable $e) {

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