<?php

namespace App\Services;

use App\Models\Booking;
use Illuminate\Support\Facades\Event;
use InvalidArgumentException;

class BookingStateService
{
    /**
     * Permitted transitions.
     */
    private array $transitions = [
        'draft' => ['pending_payment'],
        'pending_payment' => ['pending_provider_approval', 'confirmed', 'failed_payment'],
        'pending_provider_approval' => ['pending_payment', 'confirmed', 'expired', 'cancelled_by_provider', 'cancelled_by_customer'],
        'confirmed' => ['in_progress', 'cancelled_by_customer', 'cancelled_by_provider', 'disputed', 'pending_provider_approval'],
        'in_progress' => ['completed_pending_release', 'disputed'],
        'completed_pending_release' => ['released', 'disputed', 'partial_refund', 'refunded'],
        'disputed' => ['resolved', 'refunded', 'partial_refund'],
        'failed_payment' => ['pending_payment'],
    ];

    public function transition(Booking $booking, string $toStatus, array $meta = []): Booking
    {
        $from = $booking->status;
        if (! isset($this->transitions[$from]) || ! in_array($toStatus, $this->transitions[$from], true)) {
            throw new InvalidArgumentException("Invalid status transition from {$from} to {$toStatus}");
        }

        $booking->forceFill([
            'status' => $toStatus,
            'meta' => array_merge($booking->meta ?? [], ['transition_meta' => $meta]),
        ])->save();

        Event::dispatch("booking.status_changed", [$booking, $from, $toStatus, $meta]);
        $booking->statusHistory()->create([
            'from_status' => $from,
            'to_status' => $toStatus,
            'meta' => $meta,
        ]);
        $booking->customer?->notify(new \App\Notifications\BookingStatusChanged($booking, $from, $toStatus));
        $booking->provider?->notify(new \App\Notifications\BookingStatusChanged($booking, $from, $toStatus));

        return $booking->refresh();
    }
}
