<?php

namespace App\Http\Controllers\Admin;

use App\Enums\ApprovalMode;
use App\Enums\EventStatus;
use App\Enums\EventType;
use App\Enums\LocationType;
use App\Enums\ParticipationType;
use App\Enums\PricingType;
use App\Http\Controllers\Controller;
use App\Models\Event;
use App\Models\Game;
use App\Services\AuditLogger;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;

class EventController extends Controller
{
    public function __construct(private AuditLogger $auditLogger) {}

    public function index(Request $request): View
    {
        $events = Event::query()
            ->with('game')
            ->when($request->filled('status'), fn ($query) => $query->where('status', $request->string('status')))
            ->when($request->filled('q'), fn ($query) => $query->where('title', 'like', '%'.$request->string('q').'%'))
            ->latest('starts_at')
            ->paginate(15)
            ->withQueryString();

        return view('admin.events.index', compact('events'));
    }

    public function create(): View
    {
        $games = Game::orderBy('name')->get();

        return view('admin.events.create', compact('games'));
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $this->validateEvent($request);
        $validated['created_by'] = $request->user()->id;
        $validated['slug'] = $this->uniqueSlug($validated['title']);
        $validated['status'] = EventStatus::Draft;

        $event = Event::create($validated);
        $this->auditLogger->log('event.created', $event, null, $event->toArray());

        return redirect()
            ->route('admin.events.edit', $event)
            ->with('success', __('admin.actions.save'));
    }

    public function edit(Event $event): View
    {
        $games = Game::orderBy('name')->get();

        return view('admin.events.edit', compact('event', 'games'));
    }

    public function update(Request $request, Event $event): RedirectResponse
    {
        $validated = $this->validateEvent($request, $event);
        $old = $event->toArray();
        $event->update($validated);
        $this->auditLogger->log('event.updated', $event, $old, $event->fresh()->toArray());

        return back()->with('success', __('admin.actions.update'));
    }

    public function publish(Event $event): RedirectResponse
    {
        $this->authorize('publish', $event);

        $old = $event->only(['status', 'published_at']);
        $event->update([
            'status' => EventStatus::RegistrationOpen,
            'published_at' => now(),
        ]);
        $this->auditLogger->log('event.published', $event, $old, $event->only(['status', 'published_at']));

        return back()->with('success', __('admin.events.published_success'));
    }

    public function cancel(Request $request, Event $event): RedirectResponse
    {
        $this->authorize('update', $event);

        $old = $event->only(['status']);
        $event->update(['status' => EventStatus::Cancelled]);
        $this->auditLogger->log('event.cancelled', $event, $old, $event->only(['status']));

        return back()->with('success', __('admin.events.cancelled_success'));
    }

    private function validateEvent(Request $request, ?Event $event = null): array
    {
        return $request->validate([
            'game_id' => ['required', 'exists:games,id'],
            'title' => ['required', 'string', 'max:255'],
            'short_description' => ['nullable', 'string', 'max:500'],
            'description' => ['nullable', 'string'],
            'event_type' => ['required', 'in:'.implode(',', array_column(EventType::cases(), 'value'))],
            'participation_type' => ['required', 'in:'.implode(',', array_column(ParticipationType::cases(), 'value'))],
            'location_type' => ['required', 'in:'.implode(',', array_column(LocationType::cases(), 'value'))],
            'venue_name' => ['nullable', 'string', 'max:255'],
            'venue_address' => ['nullable', 'string'],
            'online_details' => ['nullable', 'string'],
            'timezone' => ['required', 'string', 'max:64'],
            'registration_opens_at' => ['nullable', 'date'],
            'registration_closes_at' => ['nullable', 'date', 'after_or_equal:registration_opens_at'],
            'starts_at' => ['required', 'date'],
            'ends_at' => ['required', 'date', 'after:starts_at'],
            'capacity' => ['nullable', 'integer', 'min:1'],
            'waitlist_enabled' => ['sometimes', 'boolean'],
            'approval_mode' => ['required', 'in:'.implode(',', array_column(ApprovalMode::cases(), 'value'))],
            'pricing_type' => ['required', 'in:'.implode(',', array_column(PricingType::cases(), 'value'))],
            'fee_amount_minor' => ['nullable', 'integer', 'min:0'],
            'currency' => ['nullable', 'string', 'size:3'],
            'payment_instructions' => ['nullable', 'string'],
            'rules' => ['nullable', 'string'],
            'prizes' => ['nullable', 'string'],
            'contact_information' => ['nullable', 'string'],
        ]);
    }

    private function uniqueSlug(string $title): string
    {
        $base = Str::slug($title);
        $slug = $base;
        $counter = 1;

        while (Event::where('slug', $slug)->exists()) {
            $slug = $base.'-'.$counter;
            $counter++;
        }

        return $slug;
    }
}
