<?php

namespace Tests\Unit;

use App\Models\Attendance;
use App\Models\AttendanceRegularization;
use App\Models\Shift;
use App\Models\User;
use App\Services\Attendance\AttendanceCalendarDayResolver;
use Carbon\Carbon;
use Tests\TestCase;

class AttendanceCalendarDayResolverTest extends TestCase
{
    protected AttendanceCalendarDayResolver $resolver;

    protected function setUp(): void
    {
        parent::setUp();
        $this->resolver = new AttendanceCalendarDayResolver;
    }

    protected function userWithShift(string $in = '09:00', string $out = '18:00'): User
    {
        $shift = new Shift([
            'clock_in_time' => $in,
            'clock_out_time' => $out,
        ]);

        $user = new User(['id' => 1]);
        $user->setRelation('shift', $shift);

        return $user;
    }

    protected function detail(?Carbon $in = null, ?Carbon $out = null): array
    {
        return [
            'clock_in' => $in,
            'clock_out' => $out,
            'clock_in_label' => $in?->format('h:i A'),
            'clock_out_label' => $out?->format('h:i A'),
            'hours' => '--',
            'sessions_detailed' => [],
            'has_data' => $in !== null,
        ];
    }

    public function test_present_when_in_and_out_within_shift(): void
    {
        $date = '2026-06-10';
        $user = $this->userWithShift();
        $attendance = new Attendance([
            'clock_in_date_time' => Carbon::parse($date.' 09:05'),
            'clock_out_date_time' => Carbon::parse($date.' 18:10'),
            'is_late' => false,
        ]);

        $result = $this->resolver->resolve(
            'present',
            $date,
            $attendance,
            null,
            $user,
            $this->detail($attendance->clock_in_date_time, $attendance->clock_out_date_time)
        );

        $this->assertSame('present', $result['visual_status']);
        $this->assertSame('Present', $result['display_status']);
    }

    public function test_late_when_clock_in_after_grace(): void
    {
        $date = '2026-06-10';
        $user = $this->userWithShift();
        $attendance = new Attendance([
            'clock_in_date_time' => Carbon::parse($date.' 09:20'),
            'clock_out_date_time' => Carbon::parse($date.' 18:00'),
        ]);

        $result = $this->resolver->resolve(
            'present',
            $date,
            $attendance,
            null,
            $user,
            $this->detail($attendance->clock_in_date_time, $attendance->clock_out_date_time)
        );

        $this->assertSame('late', $result['visual_status']);
    }

    public function test_missing_punch_out_on_past_day(): void
    {
        $date = '2026-06-01';
        $user = $this->userWithShift();
        $in = Carbon::parse($date.' 09:00');
        $attendance = new Attendance(['clock_in_date_time' => $in]);

        $result = $this->resolver->resolve(
            'present',
            $date,
            $attendance,
            null,
            $user,
            $this->detail($in, null),
            Carbon::parse('2026-06-18 12:00')
        );

        $this->assertSame('missing_punch_out', $result['visual_status']);
        $this->assertTrue($result['flags']['missing_punch_out']);
        $this->assertSame('clock-fill', $result['icon']);
    }

    public function test_in_progress_today_before_shift_end(): void
    {
        $date = '2026-06-18';
        $user = $this->userWithShift();
        $in = Carbon::parse($date.' 09:00');
        $attendance = new Attendance(['clock_in_date_time' => $in]);

        $result = $this->resolver->resolve(
            'present',
            $date,
            $attendance,
            null,
            $user,
            $this->detail($in, null),
            Carbon::parse($date.' 14:00')
        );

        $this->assertSame('in_progress', $result['visual_status']);
    }

    public function test_missing_punch_out_today_after_shift_end(): void
    {
        $date = '2026-06-18';
        $user = $this->userWithShift();
        $in = Carbon::parse($date.' 09:00');
        $attendance = new Attendance(['clock_in_date_time' => $in]);

        $result = $this->resolver->resolve(
            'present',
            $date,
            $attendance,
            null,
            $user,
            $this->detail($in, null),
            Carbon::parse($date.' 19:00')
        );

        $this->assertSame('missing_punch_out', $result['visual_status']);
    }

    public function test_regularization_pending_overlay(): void
    {
        $date = '2026-06-10';
        $user = $this->userWithShift();
        $reg = new AttendanceRegularization(['status' => AttendanceRegularization::STATUS_PENDING]);

        $result = $this->resolver->resolve(
            'absent',
            $date,
            null,
            $reg,
            $user,
            $this->detail(),
            Carbon::parse('2026-06-18')
        );

        $this->assertSame('absent', $result['visual_status']);
        $this->assertSame('pending', $result['regularization_status']);
        $this->assertStringContainsString('Regularization: Pending', $result['tooltip']);
    }

    public function test_holiday_unchanged(): void
    {
        $user = $this->userWithShift();

        $result = $this->resolver->resolve(
            'holiday',
            '2026-06-10',
            null,
            null,
            $user,
            $this->detail()
        );

        $this->assertSame('holiday', $result['visual_status']);
    }

    public function test_not_joined_shows_muted_label(): void
    {
        $user = $this->userWithShift();

        $result = $this->resolver->resolve(
            'not_joined',
            '2026-09-10',
            null,
            null,
            $user,
            $this->detail()
        );

        $this->assertSame('not_joined', $result['visual_status']);
        $this->assertSame('Not joined', $result['display_status']);
        $this->assertSame('dash-circle', $result['icon']);
    }

    public function test_is_late_arrival_for_user(): void
    {
        $user = $this->userWithShift();
        $onTime = Carbon::parse('2026-06-10 09:10');
        $late = Carbon::parse('2026-06-10 09:20');

        $this->assertFalse($this->resolver->isLateArrivalForUser($user, $onTime));
        $this->assertTrue($this->resolver->isLateArrivalForUser($user, $late));
    }
}
