<?php

namespace Tests\Feature\Catalog;

use App\Domains\Auth\Models\User;
use App\Domains\Authorization\Enums\RoleCode;
use App\Domains\Catalog\Enums\FeaturedGroupSource;
use App\Domains\Catalog\Enums\GroupLayout;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\FeaturedGroup;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType;
use Database\Seeders\AuthorizationSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;

class OnTicketFeaturedGroupControllerTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        $this->seed(AuthorizationSeeder::class);
        WebsiteType::query()->create([
            'codigo' => 'onticket',
            'nombre' => 'OnTicket',
        ]);
        WebsiteType::query()->create([
            'codigo' => 'shopit',
            'nombre' => 'Shopit',
        ]);
    }

    public function test_authentication_is_required(): void
    {
        $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertUnauthorized();
        $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload())
            ->assertUnauthorized();
        $this->putJson('/api/v1/adminapp/tenant/featured-groups/1', $this->payload())
            ->assertUnauthorized();
    }

    public function test_index_returns_only_category_groups_for_the_onticket_tenant(): void
    {
        $tenant = $this->createTenant('acme');
        $otherTenant = $this->createTenant('other');
        $first = $this->createCategoryGroup($tenant, 'Food', order: 2);
        $second = $this->createCategoryGroup($tenant, 'Tickets', order: 1);
        $this->createCategoryGroup($otherTenant, 'Other tenant');
        FeaturedGroup::query()->create([
            'tenant_code' => $tenant->codigo,
            'source_type' => FeaturedGroupSource::All,
            'product_layout' => ProductLayout::Row,
            'group_layout' => GroupLayout::Paginated,
            'group_name' => 'All products',
            'group_order' => 0,
        ]);
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->getJson('/api/v1/adminapp/tenant/featured-groups')
            ->assertOk()
            ->assertJsonCount(2, 'data')
            ->assertJsonPath('data.0.id', $second->id)
            ->assertJsonPath('data.0.category_name', 'Tickets')
            ->assertJsonPath('data.1.id', $first->id)
            ->assertJsonMissing(['category_name' => 'Other tenant'])
            ->assertJsonMissing(['group_name' => 'All products']);
    }

    public function test_store_creates_a_category_and_a_featured_horizontal_group(): void
    {
        $tenant = $this->createTenant('acme');
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $response = $this->postJson('/api/v1/adminapp/tenant/featured-groups', [
            'category_name' => 'Food',
            'is_featured' => true,
        ])
            ->assertCreated()
            ->assertJsonPath('data.code', 'food')
            ->assertJsonPath('data.category_name', 'Food')
            ->assertJsonPath('data.group_name', 'Food')
            ->assertJsonPath('data.is_featured', true)
            ->assertJsonPath('data.type', 'category')
            ->assertJsonPath('data.product_layout', 'row')
            ->assertJsonPath('data.group_layout', 'paginated');

        $categoryId = $response->json('data.category_id');
        $this->assertDatabaseHas('categorias', [
            'id' => $categoryId,
            'tenant_code' => $tenant->codigo,
            'nombre' => 'Food',
        ]);
        $this->assertDatabaseHas('featured_groups', [
            'tenant_code' => $tenant->codigo,
            'code' => 'food',
            'source_type' => 'category',
            'category_id' => $categoryId,
            'product_layout' => 'row',
            'group_layout' => 'paginated',
            'group_name' => 'Food',
        ]);
    }

    public function test_store_uses_column_with_cart_when_the_category_is_not_featured(): void
    {
        $tenant = $this->createTenant('acme');
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->postJson('/api/v1/adminapp/tenant/featured-groups', [
            'category_name' => 'Parking',
            'is_featured' => false,
        ])
            ->assertCreated()
            ->assertJsonPath('data.is_featured', false)
            ->assertJsonPath('data.product_layout', 'column_with_cart')
            ->assertJsonPath('data.group_layout', 'paginated');
    }

    public function test_update_changes_the_category_and_group_together(): void
    {
        $tenant = $this->createTenant('acme');
        $group = $this->createCategoryGroup($tenant, 'Old name', ProductLayout::ColumnWithCart);
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->putJson("/api/v1/adminapp/tenant/featured-groups/{$group->id}", [
            'category_name' => 'New name',
            'is_featured' => true,
        ])
            ->assertOk()
            ->assertJsonPath('data.code', 'old-name')
            ->assertJsonPath('data.category_name', 'New name')
            ->assertJsonPath('data.group_name', 'New name')
            ->assertJsonPath('data.is_featured', true)
            ->assertJsonPath('data.product_layout', 'row')
            ->assertJsonPath('data.group_layout', 'paginated');

        $this->assertDatabaseHas('categorias', [
            'id' => $group->category_id,
            'nombre' => 'New name',
        ]);
        $this->assertDatabaseHas('featured_groups', [
            'id' => $group->id,
            'code' => 'old-name',
            'group_name' => 'New name',
            'product_layout' => 'row',
            'group_layout' => 'paginated',
        ]);
    }

    public function test_update_rejects_groups_from_another_tenant_or_source(): void
    {
        $tenant = $this->createTenant('acme');
        $otherTenant = $this->createTenant('other');
        $otherGroup = $this->createCategoryGroup($otherTenant, 'Other');
        $allGroup = FeaturedGroup::query()->create([
            'tenant_code' => $tenant->codigo,
            'source_type' => FeaturedGroupSource::All,
            'product_layout' => ProductLayout::Row,
            'group_layout' => GroupLayout::Paginated,
            'group_name' => 'All products',
            'group_order' => 0,
        ]);
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->putJson(
            "/api/v1/adminapp/tenant/featured-groups/{$otherGroup->id}",
            $this->payload(),
        )->assertNotFound();
        $this->putJson(
            "/api/v1/adminapp/tenant/featured-groups/{$allGroup->id}",
            $this->payload(),
        )->assertNotFound();
    }

    public function test_name_and_featured_flag_are_required(): void
    {
        $tenant = $this->createTenant('acme');
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->postJson('/api/v1/adminapp/tenant/featured-groups', [
            'category_name' => '',
            'is_featured' => 'yes',
        ])
            ->assertUnprocessable()
            ->assertJsonValidationErrors(['category_name', 'is_featured']);

        $this->assertDatabaseCount('categorias', 0);
        $this->assertDatabaseCount('featured_groups', 0);
    }

    public function test_the_controller_is_not_available_for_non_onticket_tenants(): void
    {
        $tenant = $this->createTenant('store', 'shopit');
        Sanctum::actingAs($this->createAdminAppUser($tenant));

        $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertNotFound();
        $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload())
            ->assertNotFound();
    }

    public function test_a_customer_cannot_manage_onticket_featured_groups(): void
    {
        Sanctum::actingAs(User::factory()->create([
            'rol_codigo' => RoleCode::User->value,
            'tenant_codigo' => null,
        ]));

        $this->getJson('/api/v1/adminapp/tenant/featured-groups')->assertForbidden();
        $this->postJson('/api/v1/adminapp/tenant/featured-groups', $this->payload())
            ->assertForbidden();
    }

    /** @return array{category_name: string, is_featured: bool} */
    private function payload(): array
    {
        return [
            'category_name' => 'Food',
            'is_featured' => true,
        ];
    }

    private function createTenant(string $code, string $websiteType = 'onticket'): Tenant
    {
        return Tenant::query()->create([
            'codigo' => $code,
            'nombre' => ucfirst($code),
            'dominio' => "{$code}.test",
            'website_type_code' => $websiteType,
        ]);
    }

    private function createAdminAppUser(Tenant $tenant): User
    {
        return User::factory()->create([
            'rol_codigo' => RoleCode::AdminApp->value,
            'tenant_codigo' => $tenant->codigo,
        ]);
    }

    private function createCategoryGroup(
        Tenant $tenant,
        string $name,
        ProductLayout $productLayout = ProductLayout::Row,
        int $order = 0,
    ): FeaturedGroup {
        $category = Category::query()->create([
            'tenant_code' => $tenant->codigo,
            'nombre' => $name,
        ]);

        return FeaturedGroup::query()->create([
            'tenant_code' => $tenant->codigo,
            'source_type' => FeaturedGroupSource::Category,
            'category_id' => $category->id,
            'product_layout' => $productLayout,
            'group_layout' => GroupLayout::Paginated,
            'group_name' => $name,
            'group_order' => $order,
        ]);
    }
}
