<?php

namespace App\Http\Controllers\Dashboard;

use App\Enums\CatalogReviewStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreVenueRequest;
use App\Http\Requests\UpdateVenueRequest;
use App\Models\Role;
use App\Models\User;
use App\Models\Venue;
use App\Services\AuditLogger;
use App\Support\CountryAlpha2;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;

/**
 * CRUD de sedes/recintos (`venues`) para catálogo interno: staff ve todo; organizador según políticas.
 *
 * Soporta soft deletes y restauración para evitar romper eventos históricos.
 */
class VenueController extends Controller
{
    public function index(Request $request): View
    {
        $this->authorize('viewAny', Venue::class);

        $user = $request->user();
        assert($user instanceof User);

        $query = $this->scopedVenuesQuery($user)
            ->withTrashed()
            ->with(['submittedBy'])
            ->withCount('events')
            ->orderBy('name');

        // Listado con Bootstrap Table en cliente (misma UX que Pagos); tope para no saturar memoria.
        $venues = $query->limit(500)->get();

        return view('dashboard.venues.index', [
            'venues' => $venues,
        ]);
    }

    public function create(Request $request): View
    {
        $this->authorize('create', Venue::class);

        return view('dashboard.venues.create', [
            'venue' => new Venue,
            'timezones' => timezone_identifiers_list(),
            'googleMapsKey' => (string) config('services.google_maps.browser_key'),
            'googleMapsMapId' => (string) config('services.google_maps.map_id'),
            'countryLabels' => CountryAlpha2::labelsForLocale(),
        ]);
    }

    public function store(StoreVenueRequest $request, AuditLogger $auditLogger): RedirectResponse
    {
        $validated = $request->validated();

        $user = $request->user();
        assert($user instanceof User);

        $slug = $this->uniqueSlugFromName($validated['name']);

        $isStaff = $user->hasRole(Role::SLUG_SUPER_ADMIN) || $user->hasRole(Role::SLUG_ADMINISTRADOR);

        $venue = Venue::query()->create([
            'name' => $validated['name'],
            'slug' => $slug,
            'timezone' => $validated['timezone'] ?? config('app.timezone'),
            'catalog_review_status' => $isStaff ? CatalogReviewStatus::Approved : CatalogReviewStatus::PendingReview,
            'catalog_submitted_by' => $isStaff ? null : $user->id,
            'address_line_1' => $validated['address_line_1'] ?? null,
            'address_line_2' => $validated['address_line_2'] ?? null,
            'city' => $validated['city'] ?? null,
            'region' => $validated['region'] ?? null,
            'postal_code' => $validated['postal_code'] ?? null,
            'country' => $validated['country'] ?? null,
            'latitude' => isset($validated['latitude']) ? round((float) $validated['latitude'], 7) : null,
            'longitude' => isset($validated['longitude']) ? round((float) $validated['longitude'], 7) : null,
        ]);

        $auditLogger->log(
            'venue.created',
            'venues',
            __('Sede creada: :name', ['name' => $venue->name]),
            ['venue_id' => $venue->id],
            $venue,
            $request,
        );

        return redirect()
            ->route('dashboard.venues.edit', $venue)
            ->with('success', __('Recinto guardado correctamente.'));
    }

    public function edit(Request $request, Venue $venue): View
    {
        $this->authorize('update', $venue);

        $venue->loadCount('events');

        return view('dashboard.venues.edit', [
            'venue' => $venue,
            'timezones' => timezone_identifiers_list(),
            'googleMapsKey' => (string) config('services.google_maps.browser_key'),
            'googleMapsMapId' => (string) config('services.google_maps.map_id'),
            'countryLabels' => CountryAlpha2::labelsForLocale(),
        ]);
    }

    public function update(UpdateVenueRequest $request, Venue $venue, AuditLogger $auditLogger): RedirectResponse
    {
        $validated = $request->validated();

        if ($venue->name !== $validated['name']) {
            $venue->slug = $this->uniqueSlugFromName($validated['name'], $venue->id);
        }

        $venue->fill([
            'name' => $validated['name'],
            'timezone' => $validated['timezone'] ?? $venue->timezone ?? config('app.timezone'),
            'address_line_1' => $validated['address_line_1'] ?? null,
            'address_line_2' => $validated['address_line_2'] ?? null,
            'city' => $validated['city'] ?? null,
            'region' => $validated['region'] ?? null,
            'postal_code' => $validated['postal_code'] ?? null,
            'country' => $validated['country'] ?? null,
            'latitude' => isset($validated['latitude']) ? round((float) $validated['latitude'], 7) : null,
            'longitude' => isset($validated['longitude']) ? round((float) $validated['longitude'], 7) : null,
        ]);
        $venue->save();

        $auditLogger->log(
            'venue.updated',
            'venues',
            __('Sede actualizada: :name', ['name' => $venue->name]),
            ['venue_id' => $venue->id],
            $venue,
            $request,
        );

        return redirect()
            ->route('dashboard.venues.edit', $venue)
            ->with('success', __('Cambios guardados.'));
    }

    public function destroy(Request $request, Venue $venue): RedirectResponse
    {
        $this->authorize('delete', $venue);

        $name = $venue->name;
        $id = $venue->id;

        $venue->delete();

        app(AuditLogger::class)->log(
            'venue.archived',
            'venues',
            __('Sede archivada (soft delete): :name', ['name' => $name]),
            ['venue_id' => $id],
            null,
            $request,
        );

        return redirect()
            ->route('dashboard.venues.index')
            ->with('success', __('Recinto archivado. Los eventos vinculados conservan el historial.'));
    }

    public function restore(Request $request, int $id): RedirectResponse
    {
        $venue = Venue::onlyTrashed()->findOrFail($id);
        $this->authorize('restore', $venue);

        $venue->restore();

        app(AuditLogger::class)->log(
            'venue.restored',
            'venues',
            __('Sede reactivada: :name', ['name' => $venue->name]),
            ['venue_id' => $venue->id],
            $venue,
            $request,
        );

        return redirect()
            ->route('dashboard.venues.index')
            ->with('success', __('Recinto reactivado correctamente.'));
    }

    /**
     * @return Builder<Venue>
     */
    private function scopedVenuesQuery(User $user)
    {
        if ($user->hasRole(Role::SLUG_SUPER_ADMIN) || $user->hasRole(Role::SLUG_ADMINISTRADOR)) {
            return Venue::query();
        }

        return Venue::querySelectableForDashboardUser($user);
    }

    private function uniqueSlugFromName(string $name, ?int $ignoreId = null): string
    {
        $base = Str::slug($name) ?: 'sede';
        $slug = $base;
        $n = 2;
        while (Venue::withTrashed()
            ->when($ignoreId !== null, fn ($q) => $q->where('id', '!=', $ignoreId))
            ->where('slug', $slug)
            ->exists()) {
            $slug = $base.'-'.$n++;
        }

        return $slug;
    }
}
