<?php

namespace Tests\Feature\Catalog;

use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Catalog\Enums\GroupLayout;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class CatalogSearchTest extends TestCase
{
    use RefreshDatabase;

    public function test_every_tenant_gets_default_search_layouts(): void
    {
        $tenant = $this->createTenant('search-default');

        $this->assertDatabaseHas('tenants', [
            'codigo' => $tenant->codigo,
            'search_product_layout' => ProductLayout::ColumnWithImage->value,
            'search_group_layout' => GroupLayout::Paginated->value,
            'search_items_per_page' => 12,
        ]);
    }

    public function test_search_layouts_can_be_updated_on_the_tenant_and_are_returned_by_bootstrap(): void
    {
        $tenant = $this->createTenant('search-config');

        $this->putJson("/api/tenants/{$tenant->codigo}", [
            'search_product_layout' => ProductLayout::Row->value,
            'search_group_layout' => GroupLayout::SimpleVertical->value,
            'search_items_per_page' => 24,
        ])
            ->assertOk()
            ->assertJsonPath('data.search_product_layout', ProductLayout::Row->value)
            ->assertJsonPath('data.search_group_layout', GroupLayout::SimpleVertical->value)
            ->assertJsonPath('data.search_items_per_page', 24);

        $this->getJson('/api/tenants/bootstrap?'.http_build_query([
            'dominio' => $tenant->dominio,
            'path' => '/',
        ]))
            ->assertOk()
            ->assertJsonPath('data.search_product_layout', ProductLayout::Row->value)
            ->assertJsonPath('data.search_group_layout', GroupLayout::SimpleVertical->value)
            ->assertJsonPath('data.search_items_per_page', 24);
    }

    public function test_search_is_tenant_scoped_relevant_and_uses_configured_page_size(): void
    {
        $tenant = $this->createTenant('search-items');
        $otherTenant = $this->createTenant('other-search-items');
        $tenant->update(['search_items_per_page' => 4]);

        foreach (range(1, 5) as $number) {
            $this->createCatalogItem($tenant, "Running {$number}");
        }
        $exactMatch = $this->createCatalogItem($tenant, 'Running');
        $outOfStock = CatalogItem::query()->create([
            'tenant_code' => $tenant->codigo,
            'slug' => 'running-sold-out',
            'nombre' => 'Running sold out',
            'descripcion' => 'Running sold out description',
            'precio' => 100,
        ]);
        $outOfStock->variants()->create([
            'inventory_id' => Inventory::query()->create(['real_stock' => 0])->id,
        ]);
        CatalogItem::query()->create([
            'tenant_code' => $tenant->codigo,
            'inventory_id' => Inventory::query()->create(['real_stock' => 2, 'reserved_stock' => 2])->id,
            'slug' => 'running-direct-sold-out',
            'nombre' => 'Running direct sold out',
            'descripcion' => 'Running direct sold out description',
            'precio' => 100,
        ]);
        $this->createCatalogItem($tenant, 'Unrelated');
        $this->createCatalogItem($otherTenant, 'Running foreign');

        $response = $this->getJson(
            "/api/tenants/{$tenant->codigo}/catalog-items?q=running"
        );

        $response
            ->assertOk()
            ->assertJsonPath('meta.current_page', 1)
            ->assertJsonPath('meta.per_page', 4)
            ->assertJsonPath('meta.total', 6)
            ->assertJsonCount(4, 'data')
            ->assertJsonPath('data.0.id', $exactMatch->id)
            ->assertJsonMissing(['nombre' => 'Running sold out'])
            ->assertJsonMissing(['nombre' => 'Running direct sold out'])
            ->assertJsonMissing(['nombre' => 'Running foreign'])
            ->assertJsonMissing(['nombre' => 'Unrelated']);
    }

    public function test_search_validates_the_query(): void
    {
        $tenant = $this->createTenant('search-validation');

        $this->getJson("/api/tenants/{$tenant->codigo}/catalog-items?q=a")
            ->assertUnprocessable()
            ->assertJsonValidationErrors('q');
    }

    private function createCatalogItem(Tenant $tenant, string $name): CatalogItem
    {
        $inventory = Inventory::query()->create(['real_stock' => 10]);

        return CatalogItem::query()->create([
            'tenant_code' => $tenant->codigo,
            'inventory_id' => $inventory->id,
            'slug' => str($name)->slug()->toString(),
            'nombre' => $name,
            'descripcion' => "{$name} description",
            'precio' => 100,
        ]);
    }

    private function createTenant(string $code): Tenant
    {
        $headerLogo = $this->createAttachment("{$code}-header");
        $footerLogo = $this->createAttachment("{$code}-footer");

        return Tenant::query()->create([
            'codigo' => $code,
            'nombre' => ucfirst($code),
            'dominio' => "{$code}.local",
            'primary_color' => '#000000',
            'secondary_color' => '#000000',
            'danger_color' => '#000000',
            'success_color' => '#000000',
            'header_bg_color' => '#000000',
            'footer_bg_color' => '#000000',
            'header_logo_id' => $headerLogo->id,
            'footer_logo_id' => $footerLogo->id,
        ]);
    }

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