<?php

use App\Models\Ecommerce\Product\Cart\CartItem;
use App\Models\Ecommerce\Product\Product\Product;
use App\Models\User;

beforeEach(function () {
    $this->user = User::factory()->create([
        'password' => 'password',
        'phone_number' => 61929248,
    ]);

    // Helper to create product with stock
    $this->createProductWithStock = function ($stock = 10) {
        // Since we don't have factories for Channel/Inventory, and the Controller logic
        // for 'stock' check seems to rely on the 'stock' column on the products table
        // (based on CartController::index logic: if ($cartItem->product->stock < ...)),
        // we can just create a product with the stock attribute.
        // If Product factory doesn't exist, we'll create it manually.

        return Product::create([
            'name' => 'Test Product',
            'slug' => 'test-product-'.uniqid(),
            'stock' => $stock,
            'price_amount' => 100,
            'is_visible' => true,
        ]);
    };
});

test('unauthenticated user cannot access cart', function () {
    $this->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->getJson('/api/v1/carts')
        ->assertStatus(401);
});

test('authenticated user can view empty cart', function () {
    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->getJson('/api/v1/carts');

    $response->assertStatus(200)
        ->assertJson(['data' => []]);
});

test('authenticated user can store item in cart', function () {
    $product = ($this->createProductWithStock)(10);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->postJson('/api/v1/carts', [
            'product_id' => $product->id,
            'product_quantity' => 2,
        ]);

    $response->assertStatus(201);

    $this->assertDatabaseHas('cart_items', [
        'user_id' => $this->user->id,
        'product_id' => $product->id,
        'product_quantity' => 2,
    ]);
});

test('storing item updates quantity if already in cart', function () {
    $product = ($this->createProductWithStock)(10);

    // Initial add
    CartItem::create([
        'user_id' => $this->user->id,
        'product_id' => $product->id,
        'product_quantity' => 1,
    ]);

    // Update quantity
    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->postJson('/api/v1/carts', [
            'product_id' => $product->id,
            'product_quantity' => 5,
        ]);

    $response->assertStatus(201);

    $this->assertDatabaseHas('cart_items', [
        'user_id' => $this->user->id,
        'product_id' => $product->id,
        'product_quantity' => 5, // Should update to new quantity, not add
    ]);
});

test('cart validation fails if product does not exist', function () {
    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->postJson('/api/v1/carts', [
            'product_id' => 99999,
            'product_quantity' => 1,
        ]);

    // Expecting validation error.
    // Note: The custom rule ProductStockIsAvailable might handle existence check or it might fail before that.
    // The request doesn't use 'exists' rule explicitly but checks stock.
    $response->assertStatus(422)
        ->assertJsonValidationErrors(['product_id']);
});

test('cart validation fails if quantity is invalid', function () {
    $product = ($this->createProductWithStock)(10);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->postJson('/api/v1/carts', [
            'product_id' => $product->id,
            'product_quantity' => 0, // Min is 1
        ]);

    $response->assertStatus(422)
        ->assertJsonValidationErrors(['product_quantity']);
});

test('cart validation fails if stock is insufficient', function () {
    $product = ($this->createProductWithStock)(5);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->postJson('/api/v1/carts', [
            'product_id' => $product->id,
            'product_quantity' => 10,
        ]);

    $response->assertStatus(422)
        ->assertJsonValidationErrors(['product_id']); // Rule attached to product_id
});

test('authenticated user can list cart items', function () {
    $product1 = ($this->createProductWithStock)(10);
    $product2 = ($this->createProductWithStock)(10);

    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product1->id, 'product_quantity' => 2]);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product2->id, 'product_quantity' => 1]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->getJson('/api/v1/carts');

    $response->assertStatus(200)
        ->assertJsonCount(2, 'data')
        ->assertJsonStructure([
            'data' => [
                '*' => [
                    'id',
                    'user_id',
                    'product_id',
                    'product_quantity',
                    'product',
                ],
            ],
        ]);
});

test('index adjusts quantity if stock decreased', function () {
    $product = ($this->createProductWithStock)(10);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 10]);

    // Reduce stock
    $product->update(['stock' => 5]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->getJson('/api/v1/carts');

    $response->assertStatus(200);

    // Check DB
    $this->assertDatabaseHas('cart_items', [
        'user_id' => $this->user->id,
        'product_id' => $product->id,
        'product_quantity' => 5,
    ]);
});

test('index removes item if out of stock', function () {
    $product = ($this->createProductWithStock)(10);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 5]);

    // Out of stock
    $product->update(['stock' => 0]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->getJson('/api/v1/carts');

    $response->assertStatus(200)
        ->assertJsonCount(0, 'data');

    // Check DB
    $this->assertDatabaseMissing('cart_items', [
        'user_id' => $this->user->id,
        'product_id' => $product->id,
    ]);
});

test('authenticated user can remove specific item from cart', function () {
    $product = ($this->createProductWithStock)(10);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 2]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->patchJson('/api/v1/carts', [
            'product_id' => $product->id,
        ]);

    $response->assertStatus(200);

    $this->assertDatabaseMissing('cart_items', [
        'user_id' => $this->user->id,
        'product_id' => $product->id,
    ]);
});

test('remove item validation fails if product_id is missing', function () {
    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->patchJson('/api/v1/carts', []);

    $response->assertStatus(422)
        ->assertJsonValidationErrors(['product_id']);
});

test('authenticated user can clear entire cart', function () {
    $product1 = ($this->createProductWithStock)(10);
    $product2 = ($this->createProductWithStock)(10);

    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product1->id, 'product_quantity' => 2]);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product2->id, 'product_quantity' => 1]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => config('ecommerce.api.token')])
        ->deleteJson('/api/v1/carts');

    $response->assertStatus(200);

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