<?php

namespace App\Modules\HR\Attendance\Services\ExceptionDetection;

use App\Modules\HR\Attendance\Contracts\AttendanceExceptionDetectionRule;
use App\Modules\HR\Attendance\Models\AttendanceRecord;
use App\Modules\HR\Attendance\Repositories\AttendanceExceptionRepository;
use App\Modules\HR\Attendance\Support\AttendanceExceptionDedupeKey;
use App\Modules\HR\Attendance\Support\AttendanceExceptionSeverity;
use App\Modules\HR\Attendance\Support\AttendanceExceptionType;
use Carbon\CarbonImmutable;

class OverlappingAttendanceExceptionRule implements AttendanceExceptionDetectionRule
{
    public function __construct(
        private readonly AttendanceExceptionRepository $exceptions,
    ) {}

    public function run(int $tenantId, CarbonImmutable $from, CarbonImmutable $to): int
    {
        $created = 0;
        $employeeIds = AttendanceRecord::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('attendance_date', [$from->toDateString(), $to->toDateString()])
            ->distinct()
            ->pluck('employee_id');

        foreach ($employeeIds as $employeeId) {
            $rows = AttendanceRecord::query()
                ->where('tenant_id', $tenantId)
                ->where('employee_id', $employeeId)
                ->whereBetween('attendance_date', [$from->toDateString(), $to->copy()->addDay()->toDateString()])
                ->whereNotNull('check_in_at')
                ->whereNotNull('check_out_at')
                ->orderBy('attendance_date')
                ->get(['id', 'employee_id', 'attendance_date', 'check_in_at', 'check_out_at']);

            $prev = null;
            foreach ($rows as $current) {
                if ($prev !== null
                    && $prev->attendance_date->copy()->addDay()->toDateString() === $current->attendance_date->toDateString()
                    && $prev->check_out_at > $current->check_in_at) {
                    $low = min((int) $prev->id, (int) $current->id);
                    $high = max((int) $prev->id, (int) $current->id);
                    $key = AttendanceExceptionDedupeKey::forOverlap($tenantId, (int) $employeeId, $low, $high);
                    $created += (int) $this->exceptions->tryInsert(
                        $tenantId,
                        (int) $employeeId,
                        null,
                        AttendanceExceptionType::OVERLAPPING_ATTENDANCE,
                        AttendanceExceptionSeverity::CRITICAL,
                        $key,
                        ['record_ids' => [$low, $high]],
                    );
                }
                $prev = $current;
            }
        }

        return $created;
    }
}
