<?php

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 createProductForSortTest(array $attributes = []): Product
{
    $createdAt = $attributes['created_at'] ?? null;
    unset($attributes['created_at']);

    $name = $attributes['name'] ?? 'Test Product '.Str::random(5);
    $product = Product::create(array_merge([
        'name' => $name,
        'slug' => Str::slug($name),
        'is_visible' => true,
        'price_amount' => 100.00,
        'stock' => 10,
        'parent_id' => null,
    ], $attributes));

    if ($createdAt) {
        $product->created_at = $createdAt;
        $product->save();
    }

    return $product;
}

test('can sort products by price ascending', function () {
    // Arrange
    createProductForSortTest(['name' => 'Expensive', 'price_amount' => 200]);
    createProductForSortTest(['name' => 'Cheap', 'price_amount' => 100]);
    createProductForSortTest(['name' => 'Medium', 'price_amount' => 150]);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('Cheap', $response->json('data.0.name'));
    $this->assertEquals('Medium', $response->json('data.1.name'));
    $this->assertEquals('Expensive', $response->json('data.2.name'));
});

test('can sort products by price descending', function () {
    // Arrange
    createProductForSortTest(['name' => 'Expensive', 'price_amount' => 200]);
    createProductForSortTest(['name' => 'Cheap', 'price_amount' => 100]);
    createProductForSortTest(['name' => 'Medium', 'price_amount' => 150]);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('Expensive', $response->json('data.0.name'));
    $this->assertEquals('Medium', $response->json('data.1.name'));
    $this->assertEquals('Cheap', $response->json('data.2.name'));
});

test('can sort products by name ascending', function () {
    // Arrange
    createProductForSortTest(['name' => 'C Product']);
    createProductForSortTest(['name' => 'A Product']);
    createProductForSortTest(['name' => 'B Product']);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('A Product', $response->json('data.0.name'));
    $this->assertEquals('B Product', $response->json('data.1.name'));
    $this->assertEquals('C Product', $response->json('data.2.name'));
});

test('can sort products by name descending', function () {
    // Arrange
    createProductForSortTest(['name' => 'C Product']);
    createProductForSortTest(['name' => 'A Product']);
    createProductForSortTest(['name' => 'B Product']);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('C Product', $response->json('data.0.name'));
    $this->assertEquals('B Product', $response->json('data.1.name'));
    $this->assertEquals('A Product', $response->json('data.2.name'));
});

test('can sort products by created_at ascending', function () {
    // Arrange
    $p1 = createProductForSortTest(['name' => 'Oldest', 'created_at' => now()->subDays(2)]);
    $p2 = createProductForSortTest(['name' => 'Newest', 'created_at' => now()]);
    $p3 = createProductForSortTest(['name' => 'Middle', 'created_at' => now()->subDay()]);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('Oldest', $response->json('data.0.name'));
    $this->assertEquals('Middle', $response->json('data.1.name'));
    $this->assertEquals('Newest', $response->json('data.2.name'));
});

test('can sort products by created_at descending', function () {
    // Arrange
    $p1 = createProductForSortTest(['name' => 'Oldest', 'created_at' => now()->subDays(2)]);
    $p2 = createProductForSortTest(['name' => 'Newest', 'created_at' => now()]);
    $p3 = createProductForSortTest(['name' => 'Middle', 'created_at' => now()->subDay()]);

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

    // Assert
    $response->assertOk();
    $this->assertCount(3, $response->json('data'));
    $this->assertEquals('Newest', $response->json('data.0.name'));
    $this->assertEquals('Middle', $response->json('data.1.name'));
    $this->assertEquals('Oldest', $response->json('data.2.name'));
});

test('defaults to latest sort when sorting param is invalid', function () {
    // Arrange
    $p1 = createProductForSortTest(['name' => 'Oldest', 'created_at' => now()->subDays(2)]);
    $p2 = createProductForSortTest(['name' => 'Newest', 'created_at' => now()]);

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

    // Assert
    $response->assertOk();
    // Default is latest() -> descending created_at
    $this->assertEquals('Newest', $response->json('data.0.name'));
});
