<?php

namespace App\Modules\HR\Attendance\Services;

use App\Modules\HR\Attendance\Models\AttendanceCorrectionRequest;
use App\Modules\HR\Attendance\Models\AttendanceRecord;
use App\Modules\HR\Attendance\Support\AttendanceCorrectionType;
use Carbon\CarbonInterface;
use Illuminate\Validation\ValidationException;

class AttendanceCorrectionPayloadValidator
{
    public function assertForSubmit(
        string $type,
        AttendanceRecord $record,
        ?CarbonInterface $requestedIn,
        ?CarbonInterface $requestedOut,
    ): void {
        $this->requireFieldsForType($type, $requestedIn, $requestedOut);
        $this->assertEffectiveOrder($type, $record, $requestedIn, $requestedOut);
    }

    public function assertForApprove(AttendanceCorrectionRequest $correction, AttendanceRecord $record): void
    {
        $this->assertForSubmit(
            $correction->type,
            $record,
            $correction->requested_check_in,
            $correction->requested_check_out,
        );
    }

    private function requireFieldsForType(
        string $type,
        ?CarbonInterface $requestedIn,
        ?CarbonInterface $requestedOut,
    ): void {
        if ($type === AttendanceCorrectionType::MISSING_CHECKOUT && $requestedOut === null) {
            throw ValidationException::withMessages(['requested_check_out' => [__('attendance_corrections.validation.check_out_required')]]);
        }
        if ($type === AttendanceCorrectionType::WRONG_CHECKIN && $requestedIn === null) {
            throw ValidationException::withMessages(['requested_check_in' => [__('attendance_corrections.validation.check_in_required')]]);
        }
        if ($type === AttendanceCorrectionType::WRONG_CHECKOUT && $requestedOut === null) {
            throw ValidationException::withMessages(['requested_check_out' => [__('attendance_corrections.validation.check_out_required')]]);
        }
        if ($type === AttendanceCorrectionType::ATTENDANCE_DISPUTE && $requestedIn === null && $requestedOut === null) {
            throw ValidationException::withMessages(['requested_check_in' => [__('attendance_corrections.validation.at_least_one_time')]]);
        }
    }

    private function assertEffectiveOrder(
        string $type,
        AttendanceRecord $record,
        ?CarbonInterface $requestedIn,
        ?CarbonInterface $requestedOut,
    ): void {
        $in = $this->effectiveCheckIn($type, $record, $requestedIn);
        $out = $this->effectiveCheckOut($type, $record, $requestedOut);
        if ($in === null || $out === null) {
            return;
        }
        if ($out->lessThanOrEqualTo($in)) {
            throw ValidationException::withMessages([
                'requested_check_out' => [__('attendance_corrections.validation.check_out_after_check_in')],
            ]);
        }
    }

    private function effectiveCheckIn(string $type, AttendanceRecord $record, ?CarbonInterface $requestedIn): ?CarbonInterface
    {
        if ($type === AttendanceCorrectionType::WRONG_CHECKIN || $type === AttendanceCorrectionType::ATTENDANCE_DISPUTE) {
            return $requestedIn ?? $record->check_in_at;
        }

        return $record->check_in_at;
    }

    private function effectiveCheckOut(string $type, AttendanceRecord $record, ?CarbonInterface $requestedOut): ?CarbonInterface
    {
        if ($type === AttendanceCorrectionType::WRONG_CHECKOUT
            || $type === AttendanceCorrectionType::MISSING_CHECKOUT
            || $type === AttendanceCorrectionType::ATTENDANCE_DISPUTE) {
            return $requestedOut ?? $record->check_out_at;
        }

        return $record->check_out_at;
    }
}
