<?php

namespace App\Actions\Events;

use App\Enums\ApprovalMode;
use App\Enums\PaymentStatus;
use App\Enums\PricingType;
use App\Enums\RegistrationStatus;
use App\Events\RegistrationStatusChanged;
use App\Models\Event;
use App\Models\EventRegistration;
use App\Models\EventRegistrationStatusEvent;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;

class RegisterForEventAction
{
    public function execute(Event $event, User $user, array $data): EventRegistration
    {
        return DB::transaction(function () use ($event, $user, $data) {
            if (! $event->status->allowsRegistration()) {
                throw new InvalidArgumentException(__('events.registration.not_open'));
            }

            if (blank($user->phone_e164) && blank($data['contact_phone_e164'] ?? null)) {
                throw new InvalidArgumentException(__('events.registration.phone_required'));
            }

            $hasActiveRegistration = $event->registrations()
                ->where('user_id', $user->id)
                ->whereIn('status', [
                    RegistrationStatus::Pending,
                    RegistrationStatus::PendingPayment,
                    RegistrationStatus::PaymentReview,
                    RegistrationStatus::Confirmed,
                    RegistrationStatus::Waitlisted,
                    RegistrationStatus::CheckedIn,
                ])
                ->exists();

            if ($hasActiveRegistration) {
                throw new InvalidArgumentException(__('events.registration.duplicate_active'));
            }

            $profile = $user->playerProfile;
            if (! $profile) {
                throw new InvalidArgumentException(__('events.registration.profile_incomplete'));
            }

            $confirmedCount = $event->registrations()
                ->whereIn('status', [RegistrationStatus::Confirmed, RegistrationStatus::PendingPayment, RegistrationStatus::PaymentReview])
                ->count();

            $status = $this->resolveInitialStatus($event, $confirmedCount);
            $paymentStatus = $event->pricing_type === PricingType::Paid
                ? PaymentStatus::Pending
                : PaymentStatus::NotRequired;

            if ($status === RegistrationStatus::PendingPayment) {
                $paymentStatus = PaymentStatus::Pending;
            }

            $registration = EventRegistration::create([
                'event_id' => $event->id,
                'user_id' => $user->id,
                'player_profile_id' => $profile->id,
                'player_game_profile_id' => $data['player_game_profile_id'],
                'status' => $status,
                'payment_status' => $paymentStatus,
                'contact_name' => $data['contact_name'],
                'contact_email' => $data['contact_email'],
                'contact_phone_e164' => $data['contact_phone_e164'] ?? $user->phone_e164,
                'contact_whatsapp' => $data['contact_whatsapp'] ?? false,
                'user_notes' => $data['user_notes'] ?? null,
                'registered_at' => now(),
                'confirmed_at' => $status === RegistrationStatus::Confirmed ? now() : null,
                'waitlist_position' => $status === RegistrationStatus::Waitlisted
                    ? $this->nextWaitlistPosition($event)
                    : null,
            ]);

            $this->recordStatusChange($registration, null, $status, $user->id);

            event(new RegistrationStatusChanged(
                registration: $registration->load(['event', 'user']),
                previousStatus: null,
                isNewRegistration: true,
            ));

            return $registration;
        });
    }

    private function resolveInitialStatus(Event $event, int $confirmedCount): RegistrationStatus
    {
        if ($event->capacity !== null && $confirmedCount >= $event->capacity) {
            if ($event->waitlist_enabled) {
                return RegistrationStatus::Waitlisted;
            }

                throw new InvalidArgumentException(__('events.registration.capacity_full'));
        }

        if ($event->pricing_type === PricingType::Paid) {
            return RegistrationStatus::PendingPayment;
        }

        if ($event->approval_mode === ApprovalMode::AdminReview) {
            return RegistrationStatus::Pending;
        }

        return RegistrationStatus::Confirmed;
    }

    private function nextWaitlistPosition(Event $event): int
    {
        return (int) $event->registrations()
            ->where('status', RegistrationStatus::Waitlisted)
            ->max('waitlist_position') + 1;
    }

    private function recordStatusChange(
        EventRegistration $registration,
        ?RegistrationStatus $oldStatus,
        RegistrationStatus $newStatus,
        ?int $changedBy,
        ?string $reason = null,
    ): void {
        EventRegistrationStatusEvent::create([
            'event_registration_id' => $registration->id,
            'old_status' => $oldStatus,
            'new_status' => $newStatus,
            'changed_by' => $changedBy,
            'reason' => $reason,
        ]);
    }
}
