<?php

namespace App\Filament\Tenant\Pages;

use App\Filament\Tenant\Resources\EventResource;
use App\Models\Event;
use App\Models\EventType;
use App\Models\TaskCollection;
use App\Services\EventJoinTokenService;
use App\Services\Tenant\TaskCollectionImportService;
use App\Support\JoinTokenLayoutRegistry;
use App\Support\TenantOnboardingState;
use BackedEnum;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Throwable;
use UnitEnum;

class TenantOnboarding extends Page
{
    protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-sparkles';

    protected string $view = 'filament.tenant.pages.onboarding';

    protected static ?string $navigationLabel = 'Willkommen';

    protected static ?string $slug = 'willkommen';

    protected static ?string $title = 'Euer Start mit Fotospiel';

    protected static UnitEnum|string|null $navigationGroup = null;

    public string $step = 'intro';

    public array $status = [];

    public array $inviteDownloads = [];

    public array $selectedPackages = [];

    public string $eventName = '';

    public ?string $eventDate = null;

    public ?int $eventTypeId = null;

    public ?string $palette = null;

    public ?string $inviteLayout = null;

    public bool $isProcessing = false;

    protected static bool $shouldRegisterNavigation = true;

    public function mount(): void
    {
        $tenant = TenantOnboardingState::tenant();

        abort_if(! $tenant, 403);

        $this->status = TenantOnboardingState::status($tenant);

        if (TenantOnboardingState::completed($tenant)) {
            $this->redirect(EventResource::getUrl());

            return;
        }

        $this->eventDate = Carbon::now()->addWeeks(2)->format('Y-m-d');
        $this->eventTypeId = $this->getDefaultEventTypeId();
    }

    public static function shouldRegisterNavigation(): bool
    {
        $tenant = TenantOnboardingState::tenant();

        return ! TenantOnboardingState::completed($tenant);
    }

    public function start(): void
    {
        $this->step = 'packages';
    }

    public function savePackages(): void
    {
        $this->validate([
            'selectedPackages' => ['required', 'array', 'min:1'],
            'selectedPackages.*' => ['integer', 'exists:task_collections,id'],
        ], [
            'selectedPackages.required' => 'Bitte wählt mindestens ein Aufgabenpaket aus.',
        ]);

        $this->step = 'event';
    }

    public function saveEvent(): void
    {
        $this->validate([
            'eventName' => ['required', 'string', 'max:255'],
            'eventDate' => ['required', 'date'],
            'eventTypeId' => ['required', 'exists:event_types,id'],
        ]);

        $this->step = 'palette';
    }

    public function savePalette(): void
    {
        $this->validate([
            'palette' => ['required', 'string'],
        ]);

        $this->step = 'invite';
    }

    public function finish(
        TaskCollectionImportService $importService,
        EventJoinTokenService $joinTokenService
    ): void {
        $this->validate([
            'inviteLayout' => ['required', 'string'],
        ], [
            'inviteLayout.required' => 'Bitte wählt ein Layout aus.',
        ]);

        $tenant = TenantOnboardingState::tenant();

        abort_if(! $tenant, 403);

        $this->isProcessing = true;

        try {
            DB::transaction(function () use ($tenant, $importService, $joinTokenService) {
                $event = $this->createEvent($tenant);
                $this->importPackages($importService, $this->selectedPackages, $event);

                $token = $joinTokenService->createToken($event, [
                    'label' => 'Fotospiel Einladung',
                    'metadata' => [
                        'preferred_layout' => $this->inviteLayout,
                    ],
                ]);

                $settings = $tenant->settings ?? [];
                Arr::set($settings, 'branding.palette', $this->palette);
                Arr::set($settings, 'branding.primary_event_id', $event->id);
                Arr::set($settings, 'branding.preferred_invite_layout', $this->inviteLayout);
                $tenant->forceFill(['settings' => $settings])->save();

                TenantOnboardingState::markCompleted($tenant, [
                    'primary_event_id' => $event->id,
                    'selected_packages' => $this->selectedPackages,
                    'qr_layout' => $this->inviteLayout,
                ]);

                $this->inviteDownloads = $this->buildInviteDownloads($event, $token);
                $this->status = TenantOnboardingState::status($tenant);

                Notification::make()
                    ->title('Euer Setup ist bereit!')
                    ->body('Wir haben euer Event erstellt, Aufgaben importiert und euren Einladungslink vorbereitet.')
                    ->success()
                    ->send();

                $this->redirect(EventResource::getUrl('view', ['record' => $event]));
            });
        } catch (Throwable $exception) {
            report($exception);

            Notification::make()
                ->title('Setup konnte nicht abgeschlossen werden')
                ->body('Bitte prüft eure Eingaben oder versucht es später erneut.')
                ->danger()
                ->send();
        } finally {
            $this->isProcessing = false;
        }
    }

    protected function createEvent($tenant): Event
    {
        $slugBase = Str::slug($this->eventName) ?: 'event';

        do {
            $slug = Str::of($slugBase)->append('-', Str::random(6))->lower();
        } while (Event::where('slug', $slug)->exists());

        return Event::create([
            'tenant_id' => $tenant->id,
            'name' => [
                app()->getLocale() => $this->eventName,
                'de' => $this->eventName,
            ],
            'description' => null,
            'date' => $this->eventDate,
            'slug' => (string) $slug,
            'event_type_id' => $this->eventTypeId,
            'is_active' => true,
            'default_locale' => app()->getLocale(),
            'status' => 'draft',
            'settings' => [
                'appearance' => [
                    'palette' => $this->palette,
                ],
            ],
        ]);
    }

    protected function importPackages(
        TaskCollectionImportService $importService,
        array $packageIds,
        Event $event
    ): void {
        if (empty($packageIds)) {
            return;
        }

        /** @var EloquentCollection<TaskCollection> $collections */
        $collections = TaskCollection::query()
            ->whereIn('id', $packageIds)
            ->get();

        $collections->each(function (TaskCollection $collection) use ($importService, $event) {
            $importService->import($collection, $event);
        });
    }

    protected function buildInviteDownloads(Event $event, $token): array
    {
        return JoinTokenLayoutRegistry::toResponse(function (string $layoutId, string $format) use ($event, $token) {
            return route('api.v1.tenant.events.join-tokens.layouts.download', [
                'event' => $event->slug,
                'joinToken' => $token->getKey(),
                'layout' => $layoutId,
                'format' => $format,
            ]);
        });
    }

    public function getPackageListProperty(): array
    {
        return TaskCollection::query()
            ->whereNull('tenant_id')
            ->orderBy('position')
            ->get()
            ->map(fn (TaskCollection $collection) => [
                'id' => $collection->getKey(),
                'name' => $collection->name,
                'description' => $collection->description,
            ])
            ->toArray();
    }

    public function getEventTypeOptionsProperty(): array
    {
        return EventType::query()
            ->orderBy('name->'.app()->getLocale())
            ->get()
            ->mapWithKeys(function (EventType $type) {
                $name = $type->name[app()->getLocale()] ?? $type->name['de'] ?? Arr::first($type->name);

                return [$type->getKey() => $name];
            })
            ->toArray();
    }

    public function getPaletteOptionsProperty(): array
    {
        return [
            'romance' => [
                'label' => 'Rosé & Gold',
                'description' => 'Warme Rosé-Töne mit goldenen Akzenten – romantisch und elegant.',
            ],
            'sunset' => [
                'label' => 'Sonnenuntergang',
                'description' => 'Leuchtende Orange- und Pink-Verläufe für lebhafte Partys.',
            ],
            'evergreen' => [
                'label' => 'Evergreen',
                'description' => 'Sanfte Grüntöne und Naturakzente für Boho- & Outdoor-Events.',
            ],
            'midnight' => [
                'label' => 'Midnight',
                'description' => 'Tiefes Navy und Flieder – perfekt für elegante Abendveranstaltungen.',
            ],
        ];
    }

    public function getLayoutOptionsProperty(): array
    {
        return collect(JoinTokenLayoutRegistry::all())
            ->map(fn ($layout) => [
                'id' => $layout['id'],
                'name' => $layout['name'],
                'subtitle' => $layout['subtitle'] ?? '',
                'description' => $layout['description'] ?? '',
            ])
            ->toArray();
    }

    protected function getDefaultEventTypeId(): ?int
    {
        return EventType::query()->orderBy('name->'.app()->getLocale())->value('id');
    }
}
