<?php

namespace Database\Seeders;

use App\Domains\Catalog\Enums\FeaturedGroupSource;
use App\Domains\Catalog\Enums\GroupLayout;
use App\Domains\Catalog\Enums\InventoryPolicy;
use App\Domains\Catalog\Enums\InventorySubject;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\FeaturedGroup;
use App\Domains\Catalog\Services\CatalogService;
use App\Domains\Client\Models\Client;
use App\Domains\Desfile\Services\InvitationPurchaseProvisioner;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Services\TenantService;
use Illuminate\Database\Seeder;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class DesfilePuraTendenciaSeeder extends Seeder
{
    private const ONTICKET_CLIENT_CODE = 'onticket';

    private const TENANT_CODE = 'desfile_pura_tendencia';

    public function __construct(
        private readonly TenantService $tenantService,
        private readonly CatalogService $catalogService,
        private readonly InvitationPurchaseProvisioner $invitationPurchaseProvisioner,
    ) {}

    public function run(): void
    {
        $client = Client::query()->firstOrCreate(
            ['code' => self::ONTICKET_CLIENT_CODE],
            ['name' => 'OnTicket'],
        );

        $tenant = Tenant::query()->where('codigo', self::TENANT_CODE)->first();

        if ($tenant) {
            $tenant->update(['client_id' => $client->id]);
        } else {
            DB::transaction(function () use ($client): void {
                $this->createTenant($client);
                $this->createEventDate();
                $this->createEntryCatalog();
            });
        }

        $this->invitationPurchaseProvisioner->provision();
    }

    private function createTenant(Client $client): void
    {
        $this->tenantService->create([
            'client_id' => $client->id,
            'codigo' => self::TENANT_CODE,
            'nombre' => 'Desfile Pura Tendencia',
            'dominio' => 'desfile-pura-tendencia.localhost',
            'site_title' => 'Desfile Pura Tendencia',
            'event_title' => 'Desfile Pura Tendencia',
            'event_location' => 'Salón Centro Recreativo Luz y Fuerza',
            'event_date_text' => '16 de Octubre 2026',
            'primary_color' => '#BA69A9',
            'secondary_color' => '#A0A0A0',
            'danger_color' => '#FF8888',
            'success_color' => '#198754',
            'header_bg_color' => '#ffffff',
            'footer_bg_color' => '#D4441C',
            'display_categories' => false,
            'display_seach_bar' => false,
            'display_cart' => true,
            'cart_editing_policy' => 'full',
            'checkout_editing_policy' => 'disabled',
            'display_cart_item_images' => false,
            'scanner_category_validation_enabled' => false,
            'website_type_code' => 'onticket',
            'header_logo' => $this->uploadedImage(
                'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_header.png',
                'desfile_pura_tendencia_header.png',
            ),
            'footer_logo' => $this->uploadedImage(
                'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_footer.png',
                'desfile_pura_tendencia_footer.png',
            ),
            'favicon' => $this->uploadedImage(
                'images/tennants/desfile_pura_tendencia/pura_tendencia_favicon.png',
                'pura_tendencia_favicon.png',
            ),
            'footer_bg_image' => $this->uploadedImage(
                'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_footer_background.png',
                'desfile_pura_tendencia_footer_background.png',
            ),
            'extras' => [
                'heroConfig' => [
                    'title_html' => '<h1>LA NOCHE DE LA MODA</h1>',
                    'description_html' => 'Viví una experiencia de <b>Alta Costura con conducción exclusiva de Pampita</b> y las colecciones de Pucheta-Paz.',
                    'background_image_id' => $this->uploadedImage(
                        'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_hero.png',
                        'desfile_pura_tendencia_hero.png',
                    ),
                ],
            ],
        ]);
    }

    private function createEventDate(): void
    {
        $now = now();
        $validityTimeId = DB::table('validity_times')->insertGetId([
            'type' => 'fixed_window',
            'start_time' => null,
            'end_time' => null,
            'fixed_starts_at' => '2026-10-16 20:30:00',
            'fixed_expires_at' => '2026-10-16 23:59:00',
            'created_at' => $now,
            'updated_at' => $now,
        ]);

        DB::table('event_dates')->insert([
            'tenant_code' => self::TENANT_CODE,
            'validity_time_id' => $validityTimeId,
            'date' => '2026-10-16',
            'time_start' => '20:30:00',
            'time_end' => '23:59:00',
        ]);
    }

    private function createEntryCatalog(): void
    {
        $attributes = [
            'tipo' => ['name' => 'Tipo', 'options' => ['VIP + LUNCH', 'NORMAL']],
            'sector' => ['name' => 'Sector', 'options' => ['A', 'B', 'C', 'D']],
            'fila' => ['name' => 'Fila', 'options' => array_map('strval', range(1, 5))],
            'asiento' => ['name' => 'Asiento', 'options' => array_map('strval', range(1, 100))],
        ];

        foreach ($attributes as $code => $definition) {
            $attribute = Attribute::query()->create([
                'tenant_codigo' => self::TENANT_CODE,
                'codigo' => $code,
                'nombre' => $definition['name'],
                'is_required' => true,
                'metadata_schema' => null,
                'type' => 'select',
            ]);

            $attribute->options()->createMany(array_map(
                fn (string $option, int $index): array => [
                    'value' => $option,
                    'label' => $option,
                    'sort_order' => $index + 1,
                    'metadata' => null,
                ],
                $definition['options'],
                array_keys($definition['options']),
            ));
        }

        $catalogItem = $this->catalogService->create([
            'tenant_code' => self::TENANT_CODE,
            'category_id' => null,
            'brand_id' => null,
            'slug' => 'entrada',
            'nombre' => 'Entrada',
            'descripcion' => 'Entrada para Desfile Pura Tendencia',
            'precio' => 40000,
            'inventory_policy' => InventoryPolicy::Tracked->value,
            'inventory_subject' => InventorySubject::Seat->value,
            'has_tickets' => true,
            'attribute_codes' => array_keys($attributes),
            'ticket_attribute_labels' => [
                'sector' => 'Lado',
                'fila' => 'Fila',
                'asiento' => 'Asiento',
            ],
            'variants' => $this->entryVariants(),
            'images' => [
                $this->uploadedImage(
                    'images/tennants/desfile_pura_tendencia/catalog/entrada_pasarela.png',
                    'entrada_pasarela.png',
                ),
            ],
        ]);

        $this->setAttributeOrder($catalogItem);

        FeaturedGroup::query()->create([
            'tenant_code' => self::TENANT_CODE,
            'code' => 'entradas',
            'source_type' => FeaturedGroupSource::All,
            'category_id' => null,
            'product_layout' => ProductLayout::TicketSelector,
            'group_layout' => GroupLayout::Single,
            'group_name' => 'Entradas',
            'group_order' => 0,
        ]);
    }

    /** @return list<array<string, mixed>> */
    private function entryVariants(): array
    {
        $variants = [];

        foreach (['A', 'B', 'C', 'D'] as $sector) {
            $lastSeat = in_array($sector, ['B', 'D'], true) ? 16 : 17;

            foreach (range(1, 5) as $row) {
                foreach (range(1, $lastSeat) as $seat) {
                    [$type, $price] = $this->entryTypeAndPrice($sector, $row);
                    $variants[] = [
                        'real_stock' => 1,
                        'descripcion' => "Sector {$sector} - Fila {$row} - Asiento {$seat} - {$type}",
                        'precio' => $price,
                        'values' => [
                            'tipo' => $type,
                            'sector' => $sector,
                            'fila' => (string) $row,
                            'asiento' => (string) $seat,
                        ],
                    ];
                }
            }
        }

        return $variants;
    }

    private function setAttributeOrder(CatalogItem $catalogItem): void
    {
        $sortOrders = ['tipo' => 1, 'sector' => 2, 'fila' => 3, 'asiento' => 4];

        $catalogItem->itemAttributes()
            ->with('attribute:id,codigo')
            ->get()
            ->each(function ($itemAttribute) use ($sortOrders): void {
                $itemAttribute->update([
                    'sort_order' => $sortOrders[$itemAttribute->attribute->codigo],
                ]);
            });
    }

    /** @return array{string, int} */
    private function entryTypeAndPrice(string $sector, int $row): array
    {
        $prices = in_array($sector, ['A', 'C'], true)
            ? [1 => 250000, 2 => 200000, 3 => 100000, 4 => 75000, 5 => 50000]
            : [1 => 240000, 2 => 190000, 3 => 90000, 4 => 65000, 5 => 40000];

        return [$row <= 2 ? 'VIP + LUNCH' : 'NORMAL', $prices[$row]];
    }

    private function uploadedImage(string $relativePath, string $filename): UploadedFile
    {
        $path = public_path($relativePath);

        if (! is_file($path)) {
            throw new RuntimeException("Image not found at path: {$path}");
        }

        $mimeType = mime_content_type($path);

        return new UploadedFile(
            $path,
            $filename,
            is_string($mimeType) ? $mimeType : null,
            null,
            true,
        );
    }
}
