<?php

namespace App\Modules\HR\Shifts\Services;

use App\Modules\HR\Shifts\Events\ShiftCreated;
use App\Modules\HR\Shifts\Events\ShiftDeactivated;
use App\Modules\HR\Shifts\Events\ShiftReactivated;
use App\Modules\HR\Shifts\Events\ShiftUpdated;
use App\Modules\HR\Shifts\Models\Shift;
use App\Modules\HR\Shifts\Repositories\ShiftRepository;
use App\Modules\HR\Shifts\Support\ShiftScheduleEndpoints;
use Illuminate\Contracts\Events\Dispatcher;

class ShiftCrudService
{
    public function __construct(
        private readonly ShiftRepository $shifts,
        private readonly Dispatcher $events,
    ) {}

    /**
     * @param  array<string, mixed>  $data
     */
    public function create(int $tenantId, array $data, int $userId): Shift
    {
        $data = $this->normalizePayload($data);
        $data['is_night_shift'] = $this->inferNightFlag($data);
        $row = $this->shifts->create(array_merge($data, [
            'tenant_id' => $tenantId,
            'created_by' => $userId,
            'updated_by' => $userId,
        ]));
        $fresh = $row->fresh();
        $this->events->dispatch(new ShiftCreated($fresh));

        return $fresh;
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public function update(Shift $shift, array $data, int $userId): Shift
    {
        $data = $this->normalizePayload($data);
        $data['is_night_shift'] = $this->inferNightFlag($data);
        $updated = $this->shifts->update($shift, array_merge($data, ['updated_by' => $userId]));
        $this->events->dispatch(new ShiftUpdated($updated));

        return $updated;
    }

    public function deactivate(Shift $shift, int $userId): Shift
    {
        $updated = $this->shifts->update($shift, [
            'is_active' => false,
            'updated_by' => $userId,
        ]);
        $this->events->dispatch(new ShiftDeactivated($updated));

        return $updated;
    }

    public function reactivate(Shift $shift, int $userId): Shift
    {
        $updated = $this->shifts->update($shift, [
            'is_active' => true,
            'updated_by' => $userId,
        ]);
        $this->events->dispatch(new ShiftReactivated($updated));

        return $updated;
    }

    public function inferNightFlag(array $data): bool
    {
        if (! empty($data['is_night_shift'])) {
            return true;
        }
        $s = (string) ($data['start_time'] ?? '');
        $e = (string) ($data['end_time'] ?? '');

        return ShiftScheduleEndpoints::normalizeHm($e) < ShiftScheduleEndpoints::normalizeHm($s);
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    private function normalizePayload(array $data): array
    {
        return array_merge([
            'grace_minutes' => 0,
            'late_after_minutes' => 0,
            'overtime_after_minutes' => 0,
            'break_minutes' => 0,
        ], $data);
    }
}
