<?php

namespace App\Domain\Facility\Services;

use App\Domain\Facility\Enums\FacilityStatus;
use App\Domain\Facility\Events\FacilityStatusChanged;
use App\Domain\Facility\Models\Facility;
use App\Domain\Shared\Exceptions\DomainException;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class FacilityService
{
    private const VALID_TRANSITIONS = [
        'active' => ['maintenance', 'closed', 'reserved', 'unavailable'],
        'maintenance' => ['active', 'closed'],
        'closed' => ['active', 'maintenance'],
        'reserved' => ['active'],
        'unavailable' => ['active'],
    ];

    public function __construct(private SpaceLayoutService $layouts) {}

    /**
     * @param array $data          Facility attributes
     * @param User  $creator
     * @param array $activityIds   Sports this facility can host (empty = any)
     * @param array $grid          ['rows' => n, 'columns' => n] for the starting layout
     */
    public function create(array $data, User $creator, array $activityIds = [], array $grid = []): Facility
    {
        return DB::transaction(function () use ($data, $creator, $activityIds, $grid) {
            $facility = Facility::create([
                ...$data,
                'created_by' => $creator->id,
            ]);

            if ($activityIds) {
                $facility->activities()->sync($activityIds);
            }

            // Every facility gets a layout on day one. Without one the schedule
            // grid renders empty and the facility looks broken rather than new.
            $this->layouts->createDefaultLayout(
                $facility,
                $creator,
                max(1, (int) ($grid['rows'] ?? 1)),
                max(1, (int) ($grid['columns'] ?? 1)),
            );

            return $facility->fresh();
        });
    }

    public function update(Facility $facility, array $data): Facility
    {
        return DB::transaction(function () use ($facility, $data) {
            $facility->update($data);
            return $facility->fresh();
        });
    }

    public function changeStatus(Facility $facility, string $newStatus, ?User $actor = null): Facility
    {
        return DB::transaction(function () use ($facility, $newStatus, $actor) {
            $currentStatus = $facility->status->value ?? $facility->status;
            $allowed = self::VALID_TRANSITIONS[$currentStatus] ?? [];

            if (!in_array($newStatus, $allowed)) {
                throw new DomainException(
                    "لا يمكن تغيير الحالة من '{$facility->status->label()}' إلى '" . FacilityStatus::from($newStatus)->label() . "'"
                );
            }

            $facility->update(['status' => $newStatus]);

            $fresh = $facility->fresh();
            if ($actor) {
                FacilityStatusChanged::dispatch($fresh, $currentStatus, $newStatus, $actor);
            }

            return $fresh;
        });
    }

    public function delete(Facility $facility): void
    {
        DB::transaction(function () use ($facility) {
            $facility->delete();
        });
    }
}
