<?php

namespace App\Modules\HR\Shifts\Services;

use App\Modules\HR\Shifts\Models\ShiftSwapRequest;
use App\Modules\HR\Shifts\Repositories\EmployeeShiftAssignmentRepository;
use App\Modules\HR\Shifts\Repositories\ShiftWorkforceRepository;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class ShiftSwapService
{
    public function __construct(
        private readonly EmployeeShiftAssignmentRepository $assignments,
        private readonly ShiftWorkforceRepository $workforce,
    ) {}

    public function submit(int $tenantId, array $data): ShiftSwapRequest
    {
        $a = $this->assignments->lockForTenant($tenantId, (int) $data['assignment_a']);
        $b = $this->assignments->lockForTenant($tenantId, (int) $data['assignment_b']);
        if ($a === null || $b === null || $a->employee_id === $b->employee_id) {
            throw ValidationException::withMessages(['assignment_b' => __('shifts.swap.invalid')]);
        }

        return $this->workforce->createSwap([
            'tenant_id' => $tenantId,
            'employee_a' => $a->employee_id,
            'employee_b' => $b->employee_id,
            'assignment_a' => $a->id,
            'assignment_b' => $b->id,
            'date' => $data['date'],
            'status' => 'pending',
        ]);
    }

    public function review(int $tenantId, int $id, bool $approve, int $reviewerId): ShiftSwapRequest
    {
        return DB::transaction(function () use ($tenantId, $id, $approve, $reviewerId): ShiftSwapRequest {
            $swap = $this->workforce->lockSwap($tenantId, $id);
            abort_if($swap === null, 404);
            if ($swap->status !== 'pending') {
                return $swap;
            }
            if ($approve) {
                $this->createOverrides($swap, $reviewerId);
            }

            return $this->workforce->updateSwap($swap, [
                'status' => $approve ? 'approved' : 'rejected',
                'reviewed_by' => $reviewerId,
                'reviewed_at' => now(),
            ]);
        });
    }

    private function createOverrides(ShiftSwapRequest $swap, int $reviewerId): void
    {
        $a = $this->assignments->lockForTenant((int) $swap->tenant_id, (int) $swap->assignment_a);
        $b = $this->assignments->lockForTenant((int) $swap->tenant_id, (int) $swap->assignment_b);
        abort_if($a === null || $b === null, 409);
        $day = CarbonImmutable::parse($swap->date);
        foreach ([[$a, $b], [$b, $a]] as [$employeeSide, $shiftSide]) {
            $this->assignments->create([
                'tenant_id' => $swap->tenant_id,
                'employee_id' => $employeeSide->employee_id,
                'shift_id' => $shiftSide->shift_id,
                'starts_at' => $day->startOfDay(),
                'ends_at' => $day->endOfDay(),
                'is_active' => false,
                'assigned_by' => $reviewerId,
            ]);
        }
    }
}
