<?php

use App\Models\Ecommerce\Product\Category\Category;
use App\Models\Ecommerce\Product\Product\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Str;

uses(RefreshDatabase::class);

beforeEach(function () {
    Config::set('ecommerce.api.token', 'test-token');
});

function createCategory(array $attributes = []): Category
{
    $name = $attributes['name'] ?? 'Test Category '.Str::random(5);
    // Handle name translation if it's not an array
    $nameValue = is_array($name) ? $name : ['en' => $name];
    $slug = Str::slug(is_array($name) ? ($name['en'] ?? reset($name)) : $name);

    return Category::create(array_merge([
        'name' => $nameValue,
        'slug' => $slug,
        'is_visible' => true,
        'sort_order' => 1,
        'type' => 'default', // Add type default to pass the filter
    ], $attributes));
}

function createProduct(array $attributes = []): Product
{
    $name = $attributes['name'] ?? 'Test Product '.Str::random(5);

    return Product::create(array_merge([
        'name' => $name,
        'slug' => Str::slug($name),
        'is_visible' => true,
        'price_amount' => 100.00,
        'stock' => 10,
        'parent_id' => null,
    ], $attributes));
}

test('can list categories', function () {
    // Arrange
    createCategory(['name' => 'Category 1']);
    createCategory(['name' => 'Category 2']);
    createCategory(['name' => 'Category 3']);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories');

    // Assert
    $response->assertOk()
        ->assertJsonStructure([
            'data' => [
                '*' => [
                    'id',
                    'name',
                    'slug',
                ],
            ],
        ]);

    $this->assertCount(3, $response->json('data'));
});

test('can filter categories by type root', function () {
    // Arrange
    $parent = createCategory(['name' => 'Parent']);
    createCategory(['name' => 'Child', 'parent_id' => $parent->id]);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories?type=root');

    // Assert
    $response->assertOk();
    $this->assertCount(1, $response->json('data'));
    $this->assertEquals($parent->id, $response->json('data.0.id'));
});

test('can filter categories by type tree', function () {
    // Arrange
    $parent = createCategory(['name' => 'Parent']);
    $child = createCategory(['name' => 'Child', 'parent_id' => $parent->id]);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories?type=tree');

    // Assert
    $response->assertOk();
    // Tree view should return root categories with children nested (or however toTree() works)
    // Assuming toTree() nests children under 'children' key or similar structure
    // CategoryRepository::get() calls $data->toTree() which usually returns roots with children loaded
    $this->assertCount(1, $response->json('data'));
    $this->assertEquals($parent->id, $response->json('data.0.id'));
    // Since toTree is used, we expect structure to reflect hierarchy
    // Depending on implementation, checking count of roots is good start.
});

test('validates category index request params', function () {
    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories?type=invalid');

    // Assert
    $response->assertUnprocessable(); // 422
    $response->assertJsonValidationErrors(['type']);
});

test('does not list invisible categories', function () {
    // Arrange
    createCategory(['name' => 'Visible', 'is_visible' => true]);
    createCategory(['name' => 'Invisible', 'is_visible' => false]);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories');

    // Assert
    $response->assertOk();
    $this->assertCount(1, $response->json('data'));
    $this->assertEquals('Visible', $response->json('data.0.name'));
});

test('can show a specific category', function () {
    // Arrange
    $category = createCategory(['name' => 'Test Category']);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson("/api/v1/categories/{$category->id}");

    // Assert
    $response->assertOk()
        ->assertJson([
            'data' => [
                'id' => $category->id,
                'name' => 'Test Category',
            ],
        ]);
});

test('returns 404 for non-existent category', function () {
    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories/99999');

    // Assert
    $response->assertNotFound();
});

test('returns 404 for invalid category id format', function () {
    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson('/api/v1/categories/invalid-id');

    // Assert
    $response->assertNotFound();
});

test('can list products for a category', function () {
    // Arrange
    $category = createCategory();
    $products = collect(range(1, 5))->map(fn () => createProduct());

    // Attach products to category
    $category->products()->attach($products->pluck('id'));

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson("/api/v1/categories/{$category->id}/products");

    // Assert
    $response->assertOk()
        ->assertJsonStructure([
            'data' => [
                '*' => [
                    'id',
                    'name',
                ],
            ],
        ]);

    $this->assertCount(5, $response->json('data'));
});

test('does not list invisible products for a category', function () {
    // Arrange
    $category = createCategory();
    $visibleProduct = createProduct(['is_visible' => true]);
    $invisibleProduct = createProduct(['is_visible' => false]);

    // Attach products to category
    $category->products()->attach([$visibleProduct->id, $invisibleProduct->id]);

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson("/api/v1/categories/{$category->id}/products");

    // Assert
    $response->assertOk();
    $this->assertCount(1, $response->json('data'));
    $this->assertEquals($visibleProduct->id, $response->json('data.0.id'));
});

test('returns empty product list for category with no products', function () {
    // Arrange
    $category = createCategory();

    // Act
    $response = $this->withHeaders([
        'Api-Token' => 'test-token',
        'Accept' => 'application/json',
    ])->getJson("/api/v1/categories/{$category->id}/products");

    // Assert
    $response->assertOk();
    $this->assertCount(0, $response->json('data'));
});
