<?php

namespace Tests\Feature;

use App\Models\AttendanceEvent;
use App\Models\DailyAttendance;
use App\Models\Employee;
use App\Models\Site;
use App\Services\AttendanceComputer;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Tests\TestCase;

class DailyComputationTest extends TestCase
{
    use RefreshDatabase;

    public function test_late_in_and_early_out_are_flagged(): void
    {
        $site = Site::factory()->create();
        $employee = Employee::factory()->create();
        $date = Carbon::parse('2026-07-01');

        AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'IN', 'ts' => $date->copy()->setTime(9, 45),
            'event_uuid' => (string) Str::uuid(),
        ]);
        AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'OUT', 'ts' => $date->copy()->setTime(17, 30),
            'event_uuid' => (string) Str::uuid(),
        ]);

        (new AttendanceComputer)->computeForDate($date);

        $row = DailyAttendance::where('employee_id', $employee->id)->where('date', $date->toDateString())->first();
        $this->assertTrue($row->late);
        $this->assertTrue($row->early_out);
        $this->assertEquals('present', $row->status);
    }

    public function test_on_time_full_day_is_not_flagged(): void
    {
        $site = Site::factory()->create();
        $employee = Employee::factory()->create();
        $date = Carbon::parse('2026-07-01');

        AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'IN', 'ts' => $date->copy()->setTime(9, 15),
            'event_uuid' => (string) Str::uuid(),
        ]);
        AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'OUT', 'ts' => $date->copy()->setTime(18, 30),
            'event_uuid' => (string) Str::uuid(),
        ]);

        (new AttendanceComputer)->computeForDate($date);

        $row = DailyAttendance::where('employee_id', $employee->id)->where('date', $date->toDateString())->first();
        $this->assertFalse($row->late);
        $this->assertFalse($row->early_out);
    }

    public function test_employee_with_no_events_is_marked_absent(): void
    {
        $employee = Employee::factory()->create();
        $date = Carbon::parse('2026-07-01');

        (new AttendanceComputer)->computeForDate($date);

        $row = DailyAttendance::where('employee_id', $employee->id)->where('date', $date->toDateString())->first();
        $this->assertEquals('absent', $row->status);
        $this->assertNull($row->first_in);
    }

    public function test_corrected_events_are_ignored_in_computation(): void
    {
        $site = Site::factory()->create();
        $employee = Employee::factory()->create();
        $date = Carbon::parse('2026-07-01');

        $original = AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'IN', 'ts' => $date->copy()->setTime(11, 0),
            'event_uuid' => (string) Str::uuid(),
        ]);

        $correction = AttendanceEvent::factory()->create([
            'employee_id' => $employee->id, 'site_id' => $site->id,
            'direction' => 'IN', 'ts' => $date->copy()->setTime(9, 0),
            'event_uuid' => (string) Str::uuid(),
            'corrects_event_id' => $original->id,
        ]);
        $original->update(['corrected_by' => $correction->id]);

        (new AttendanceComputer)->computeForDate($date);

        $row = DailyAttendance::where('employee_id', $employee->id)->where('date', $date->toDateString())->first();
        $this->assertEquals($date->copy()->setTime(9, 0)->toDateTimeString(), $row->first_in->toDateTimeString());
        $this->assertFalse($row->late);
    }
}
