<?php

namespace Modules\SpecialAttendance\Http\Repositories;

use Carbon\Carbon;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use App\Models\Hrm\Leave\LeaveRequest;
use App\Helpers\CoreApp\Traits\DateHandler;
use App\Models\Hrm\Leave\LeaveRequestDetail;
use Modules\SpecialAttendance\Entities\DutyCalendar;
use App\Models\coreApp\Relationship\RelationshipTrait;

class DutyCalendarRepository
{
    use RelationshipTrait, DateHandler;

    public function store($employee, $dateRange)
    {
        try {
            DB::beginTransaction();

            $joiningDate = $employee->joining_date ? Carbon::parse($employee->joining_date) : null;
            $dates       = $this->getDatesRange($dateRange);

            foreach ($dates ?? [] as $date) {
                $date = Carbon::parse($date);

                if ($joiningDate && $date->lt($joiningDate)) {
                    continue;
                }

                $holidays   = json_decode($employee->holidays, true) ?? [];
                $holiday_id = $holidays[$date->toDateString()] ?? null;

                // Check approved leave request exist
                $leaveRequestDetail = LeaveRequestDetail::where('user_id', $employee->id)
                    ->where('date', $date)
                    ->where('is_approved', 1)
                    ->first();

                $leave_id = $leaveRequestDetail ? $leaveRequestDetail->leave_request_id : null;

                $weekends = $employee->weekends ?? [];

                $isWeekend = ! $holiday_id && ! $leave_id && in_array(Str::lower($date->format('l')), $weekends) ? 1 : 0;

                DutyCalendar::firstOrCreate([
                    'employee_id' => $employee->id,
                    'date'        => $date->toDateString(),
                    'company_id'  => $employee->company_id,
                ], [
                    'branch_id'        => $employee->branch_id,
                    'duty_schedule_id' => ! $holiday_id && ! $leave_id && ! $isWeekend ? $employee->duty_schedule_id : null,
                    'holiday_id'       => $holiday_id,
                    'leave_id'         => $leave_id,
                    'is_weekend'       => $isWeekend,
                    'created_by'       => auth()->id() ?? 1,
                ]);
            }

            DB::commit();

            return true;
        } catch (\Throwable $th) {
            DB::rollBack();
            throw $th;
        }
    }
    public function getLeaveDatesForMonth($employee_id, $month)
    {
        $startOfMonth = Carbon::parse($month)->startOfMonth();
        $endOfMonth = Carbon::parse($month)->endOfMonth();

        $leaves = LeaveRequest::where(function ($query) use ($startOfMonth, $endOfMonth) {
            $query->whereBetween('leave_from', [$startOfMonth, $endOfMonth])
                ->orWhereBetween('leave_to', [$startOfMonth, $endOfMonth])
                ->orWhere(function ($query) use ($startOfMonth, $endOfMonth) {
                    $query->where('leave_from', '<', $startOfMonth)
                        ->where('leave_to', '>', $endOfMonth);
                });
        })
            ->where('user_id', $employee_id)
            ->get();

        $leaveDates = $leaves->flatMap(function ($leave) use ($startOfMonth, $endOfMonth) {
            $start = Carbon::parse($leave->start_date)->max($startOfMonth);
            $end = Carbon::parse($leave->end_date)->min($endOfMonth);

            return collect(range($start->day, $end->day))
                ->mapWithKeys(function ($day) use ($start, $leave) {
                    $date = $start->copy()->day($day)->toDateString();

                    return [$date => $leave->id];
                });
        })->unique()->toArray();

        return $leaveDates;
    }

    public function getDatesRange($dateRange)
    {
        $dateRange = explode(' - ', $dateRange);

        $fromDate = $this->databaseFormat($dateRange[0]);
        $toDate   = $this->databaseFormat($dateRange[1]);

        $start = \Carbon\Carbon::parse($fromDate);
        $end   = \Carbon\Carbon::parse($toDate);

        $dates = [];

        while ($start->lte($end)) {
            $dates[] = $start->format('Y-m-d');
            $start->addDay();
        }

        return $dates;
    }

    public function assignLeaveInDutyCalendarByDate($employee_id, $date, $leave_id)
    {
        $dutyCalendar = DutyCalendar::where([
            'employee_id' => $employee_id,
            'date' => $date,
        ])->first();

        DutyCalendar::updateOrCreate([
            'employee_id' => $employee_id,
            'date' => $date,
        ], [
            'company_id' => User::where('id', $employee_id)->first()?->company_id,
            'duty_schedule_id' => null,
            'leave_id' => $leave_id,
            'is_weekend' => @base_settings('is_weekend_carry_on_leave') && $dutyCalendar ? $dutyCalendar->is_weekend : 0,
            'holiday_id' => @base_settings('is_holiday_carry_on_leave') && $dutyCalendar ? $dutyCalendar->holiday_id : null,
            'created_by' => auth()->id() ?? 1,
        ]);
    }
}
