<?php

namespace App\Modules\HR\Attendance\Services;

use App\Modules\HR\Attendance\Support\AttendanceRecordStatus;
use App\Modules\HR\Employees\Models\Employee;
use App\Modules\HR\Shifts\Services\ShiftResolutionService;
use App\Modules\HR\Shifts\Support\ShiftOvertimePreview;
use App\Modules\HR\Shifts\Support\ShiftScheduleEndpoints;
use App\Modules\HR\Attendance\Repositories\AttendancePolicyRepository;
use Carbon\CarbonImmutable;

class AttendancePunchMetricsService
{
    public function __construct(
        private readonly ShiftResolutionService $shifts,
        private readonly AttendanceLateStatusResolver $lateStatus,
        private readonly EarlyLeaveDetectionService $earlyLeave,
        private readonly AttendancePolicyRepository $policies,
    ) {}

    public function statusAtCheckIn(Employee $employee, string $date, CarbonImmutable $checkIn): string
    {
        [$threshold] = $this->thresholdAndHalfDay($employee, $date, $checkIn);

        return $checkIn->gt($threshold)
            ? AttendanceRecordStatus::LATE
            : AttendanceRecordStatus::PRESENT;
    }

    /**
     * @return array{status: string, overtime_minutes: int, early_leave_minutes: int}
     */
    public function atCheckOut(
        Employee $employee,
        string $date,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
    ): array {
        [$threshold, $halfDay] = $this->thresholdAndHalfDay($employee, $date, $checkIn);
        $context = $this->shifts->resolveContextForAttendanceDate($employee, $date, $checkIn);
        $overtime = $context === null
            ? 0
            : ShiftOvertimePreview::minutesPastOvertimeThreshold($context->shift, $date, $checkOut);

        return [
            'status' => $this->lateStatus->resolve($checkIn, $checkOut, $threshold, $halfDay),
            'overtime_minutes' => $overtime,
            'early_leave_minutes' => $this->earlyLeave->minutes($employee, $date, $checkOut),
        ];
    }

    /**
     * @return array{CarbonImmutable, float}
     */
    private function thresholdAndHalfDay(
        Employee $employee,
        string $date,
        CarbonImmutable $checkIn,
    ): array {
        $context = $this->shifts->resolveContextForAttendanceDate($employee, $date, $checkIn);
        $policyGrace = $this->policies->forTenant((int) $employee->tenant_id)?->late_grace_minutes;
        if ($context !== null) {
            $threshold = $context->latenessThreshold;
            if ($policyGrace !== null) {
                $threshold = ShiftScheduleEndpoints::shiftStartOnDate(
                    $context->shift,
                    CarbonImmutable::parse($date, $checkIn->getTimezone()),
                )->addMinutes((int) $policyGrace);
            }

            return [$threshold, $context->halfDayMaxHours];
        }

        $expected = (string) config('attendance.expected_start', '09:00');
        $grace = (int) ($policyGrace ?? config('attendance.late_grace_minutes', 0));

        return [
            CarbonImmutable::parse($date.' '.$expected, $checkIn->getTimezone())->addMinutes($grace),
            (float) config('attendance.half_day_max_hours', 4.5),
        ];
    }
}
