<?php

namespace Modules\Booking\Actions;

use Modules\Booking\Enums\BookingStatus;
use Modules\Booking\Exceptions\BookingCannotBeCancelledException;
use Modules\Booking\Models\Booking;
use Modules\Payment\Actions\RefundBookingAction;

/**
 * A pending_payment booking has no money moved yet, so it cancels directly.
 * A confirmed (paid) booking is cancelled by refunding it in full first —
 * delegates to RefundBookingAction (Payment module); the booking only
 * actually flips to cancelled once that refund succeeds, via
 * RefundProcessed/MarkBookingRefunded, not here (domain.md §5). Any other
 * status (already cancelled/expired) is rejected outright.
 */
class CancelBookingAction
{
    private const CANCELLATION_REFUND_REASON = 'Booking cancellation';

    public function __construct(
        private RefundBookingAction $refundBookingAction,
    ) {}

    public function handle(Booking $booking, ?int $requestedBy = null): Booking
    {
        if ($booking->status === BookingStatus::Confirmed) {
            $this->refundBookingAction->handle(
                $booking,
                (string) $booking->price,
                self::CANCELLATION_REFUND_REASON,
                $requestedBy,
            );

            return $booking->refresh();
        }

        if ($booking->status !== BookingStatus::PendingPayment) {
            throw BookingCannotBeCancelledException::notPendingPayment($booking);
        }

        $booking->update(['status' => BookingStatus::Cancelled]);

        return $booking;
    }
}
