<?php

namespace App\Services\Attendance;

use Carbon\CarbonImmutable;

class AttendanceCalculator
{
    public function calculate(array $punches, array $shift, array $rules): array
    {
        $checkIn = $this->firstPunch($punches, 'check_in');
        $checkOut = $this->lastPunch($punches, 'check_out');

        if (! $checkIn || ! $checkOut) {
            return [
                'status' => 'incomplete',
                'missing_punch' => true,
                'working_minutes' => 0,
                'late_minutes' => 0,
                'early_out_minutes' => 0,
                'overtime_minutes' => 0,
            ];
        }

        $start = CarbonImmutable::parse($shift['start_time']);
        $end = CarbonImmutable::parse($shift['end_time']);
        $in = CarbonImmutable::parse($checkIn['punched_at']);
        $out = CarbonImmutable::parse($checkOut['punched_at']);
        $grace = (int) ($shift['grace_minutes'] ?? 0);

        return [
            'status' => 'present',
            'missing_punch' => false,
            'working_minutes' => max(0, $in->diffInMinutes($out)),
            'late_minutes' => max(0, $start->addMinutes($grace)->diffInMinutes($in, false)),
            'early_out_minutes' => max(0, $out->diffInMinutes($end, false)),
            'overtime_minutes' => max(0, $end->diffInMinutes($out, false)),
            'applied_rules' => $this->applyRules($rules),
        ];
    }

    private function firstPunch(array $punches, string $type): ?array
    {
        foreach ($punches as $punch) {
            if (($punch['type'] ?? null) === $type) {
                return $punch;
            }
        }

        return null;
    }

    private function lastPunch(array $punches, string $type): ?array
    {
        $matched = array_values(array_filter($punches, fn ($punch) => ($punch['type'] ?? null) === $type));

        return $matched ? $matched[array_key_last($matched)] : null;
    }

    private function applyRules(array $rules): array
    {
        usort($rules, fn ($left, $right) => ($left['priority'] ?? 100) <=> ($right['priority'] ?? 100));

        return array_column($rules, 'key');
    }
}
