<?php

namespace Tests\Feature\Seeders;

use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Catalog\Enums\FeaturedGroupSource;
use App\Domains\Catalog\Enums\GroupLayout;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\FeaturedGroup;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Ticket\Enums\ValidityTimeType;
use App\Domains\Ticket\Models\ValidityTime;
use Database\Seeders\AttributeSeeder;
use Database\Seeders\FiestaFutbolInfantilProductSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class FiestaFutbolInfantilProductSeederTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_seeds_the_configurable_catalog_with_its_categories(): void
    {
        $headerLogo = $this->attachment('header');
        $footerLogo = $this->attachment('footer');
        $tenant = Tenant::query()->create([
            'codigo' => 'fiesta_futbol_infantil',
            'nombre' => 'Fiesta Fútbol Infantil',
            'dominio' => 'fiesta-futbol-infantil.localhost',
            'primary_color' => '#00973F',
            'secondary_color' => '#A0A0A0',
            'danger_color' => '#FF8888',
            'success_color' => '#198754',
            'header_bg_color' => '#ffffff',
            'footer_bg_color' => '#015327',
            'header_logo_id' => $headerLogo->id,
            'footer_logo_id' => $footerLogo->id,
        ]);

        $this->seed([AttributeSeeder::class, FiestaFutbolInfantilProductSeeder::class]);
        $this->seed([AttributeSeeder::class, FiestaFutbolInfantilProductSeeder::class]);

        $this->assertSame('9, 10, 11 y 12 de Octubre 2026', $tenant->fresh()->event_date_text);
        $this->assertCount(4, $tenant->eventDates);
        $this->assertCount(4, ValidityTime::query()->whereHas('eventDate', fn ($query) => $query
            ->where('tenant_code', $tenant->codigo))->get());
        $this->assertTrue($tenant->eventDates()->with('validityTime')->get()->every(
            fn ($eventDate): bool => $eventDate->validityTime->type === ValidityTimeType::FixedWindow
                && $eventDate->validityTime->fixed_starts_at->format('Y-m-d H:i:s') === $eventDate->date->format('Y-m-d').' 00:00:00'
                && $eventDate->validityTime->fixed_expires_at->format('Y-m-d H:i:s') === $eventDate->date->format('Y-m-d').' 23:59:59'
        ));

        $this->assertSame(
            ['color', 'event_date', 'horario', 'servicio', 'talle', 'tipo_alojamiento'],
            Attribute::query()->where('tenant_codigo', $tenant->codigo)->orderBy('codigo')->pluck('codigo')->all(),
        );
        $this->assertSame(
            ['Alojamientos', 'Comidas', 'Entradas', 'Merchandising'],
            Category::query()
                ->where('tenant_code', $tenant->codigo)
                ->orderBy('nombre')
                ->pluck('nombre')
                ->all(),
        );
        $this->assertSame(
            ['abono', 'alojamiento', 'camiseta', 'comida'],
            CatalogItem::query()->where('tenant_code', $tenant->codigo)->orderBy('slug')->pluck('slug')->all(),
        );
        $this->assertSame(
            ['camiseta', 'alojamiento', 'abono', 'comida'],
            CatalogItem::query()
                ->where('tenant_code', $tenant->codigo)
                ->orderBy('group_order')
                ->pluck('slug')
                ->all(),
        );
        $this->assertTrue(
            CatalogItem::query()
                ->where('tenant_code', $tenant->codigo)
                ->get()
                ->every(fn (CatalogItem $item): bool => $item->has_tickets),
        );

        $expectedVariantCounts = [
            'camiseta' => 12,
            'alojamiento' => 2,
            'comida' => 24,
            'abono' => 1,
        ];
        foreach ($expectedVariantCounts as $slug => $count) {
            $item = CatalogItem::query()->where('tenant_code', $tenant->codigo)->where('slug', $slug)->sole();
            $this->assertCount($count, $item->variants);
        }

        $variantStocks = CatalogItem::query()
            ->where('tenant_code', $tenant->codigo)
            ->with('variants.inventory')
            ->get()
            ->flatMap(fn (CatalogItem $item) => $item->variants)
            ->map(fn ($variant): int => $variant->inventory->real_stock);
        $this->assertGreaterThan($variantStocks->count() / 2, $variantStocks->filter(fn (int $stock): bool => $stock > 5)->count());
        $this->assertNotEmpty($variantStocks->filter(fn (int $stock): bool => $stock === 0));
        $this->assertNotEmpty($variantStocks->filter(fn (int $stock): bool => $stock >= 1 && $stock <= 5));

        $this->assertSame(
            [
                'abono' => 'Entradas',
                'alojamiento' => 'Alojamientos',
                'camiseta' => 'Merchandising',
                'comida' => 'Comidas',
            ],
            CatalogItem::query()
                ->where('tenant_code', $tenant->codigo)
                ->with('category')
                ->orderBy('slug')
                ->get()
                ->mapWithKeys(fn (CatalogItem $item): array => [$item->slug => $item->category?->nombre])
                ->all(),
        );

        $abono = CatalogItem::query()
            ->where('tenant_code', $tenant->codigo)
            ->where('slug', 'abono')
            ->with('itemAttributes.attribute', 'variants.eventDates')
            ->sole();
        $dateAttribute = $abono->itemAttributes->firstWhere('attribute.codigo', 'event_date');
        $this->assertTrue($dateAttribute->allow_multi_select);
        $this->assertFalse($dateAttribute->show_in_selector);
        $this->assertEqualsCanonicalizing(
            [4],
            $abono->variants->map(fn ($variant): int => $variant->eventDates->count())->all(),
        );

        $food = CatalogItem::query()
            ->where('tenant_code', $tenant->codigo)
            ->where('slug', 'comida')
            ->with('variants')
            ->sole();
        $this->assertSame('4000.00', $food->precio);
        $this->assertCount(24, $food->variants->pluck('descripcion')->unique());
        $this->assertEqualsCanonicalizing(
            ['4000.00', '8000.00', '10000.00'],
            $food->variants->pluck('precio')->unique()->values()->all(),
        );
        $this->assertTrue($food->variants->every(
            fn ($variant): bool => $variant->descripcion !== null && $variant->precio !== null
        ));

        $featuredGroup = FeaturedGroup::query()->where('tenant_code', $tenant->codigo)->sole();
        $this->assertSame('productos', $featuredGroup->code);
        $this->assertSame(FeaturedGroupSource::All, $featuredGroup->source_type);
        $this->assertSame(ProductLayout::Row, $featuredGroup->product_layout);
        $this->assertSame(GroupLayout::SimpleVertical, $featuredGroup->group_layout);
        $this->assertNull($featuredGroup->category_id);
    }

    private function attachment(string $name): Attachment
    {
        return Attachment::query()->create([
            'path' => "tests/{$name}.png",
            'filename' => "{$name}.png",
            'type' => AttachmentType::Image,
            'mime_type' => 'image/png',
        ]);
    }
}
