<?php

namespace App\Actions\Events;

use App\Enums\PaymentStatus;
use App\Enums\RegistrationStatus;
use App\Models\EventRegistration;
use App\Models\User;
use App\Services\AuditLogger;
use App\Services\RegistrationStatusService;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;

class CancelRegistrationAction
{
    public function __construct(
        private RegistrationStatusService $registrationStatus,
        private AuditLogger $auditLogger,
    ) {}

    public function execute(EventRegistration $registration, User $actor, ?string $reason = null): EventRegistration
    {
        return DB::transaction(function () use ($registration, $actor, $reason) {
            if (! $registration->status->isActive()) {
                throw new InvalidArgumentException(__('events.errors.invalid_status'));
            }

            $heldSpot = in_array($registration->status, RegistrationStatusService::CAPACITY_HOLDING_STATUSES, true);
            $oldStatus = $registration->status;

            $this->registrationStatus->record(
                $registration,
                RegistrationStatus::Cancelled,
                $oldStatus,
                $actor,
                $reason ?? 'Registration cancelled',
            );

            $registration->update([
                'cancelled_at' => now(),
                'payment_status' => PaymentStatus::Cancelled,
                'waitlist_position' => null,
            ]);

            $this->auditLogger->log('registration.cancelled', $registration, ['status' => $oldStatus->value], ['status' => RegistrationStatus::Cancelled->value]);

            if ($heldSpot) {
                $this->promoteNextWaitlisted($registration->event_id);
            }

            return $registration->fresh(['event', 'user']);
        });
    }

    private function promoteNextWaitlisted(int $eventId): void
    {
        $next = EventRegistration::query()
            ->where('event_id', $eventId)
            ->where('status', RegistrationStatus::Waitlisted)
            ->orderBy('waitlist_position')
            ->first();

        if ($next === null) {
            return;
        }

        app(PromoteWaitlistAction::class)->execute($next, auth()->user() ?? $next->user, 'Auto-promoted after cancellation');
    }
}
