<?php

use App\Models\Ecommerce\Channel\Channel;
use App\Models\Ecommerce\Product\Cart\CartItem;
use App\Models\Ecommerce\Product\Order\Order;
use App\Models\Ecommerce\Product\Order\Payment\OrderPayment;
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
use App\Models\Ecommerce\Product\Product\Product;
use App\Models\System\Settings\Location\Region;
use App\Models\System\Settings\Payments\PaymentType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;

uses(RefreshDatabase::class);

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

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

    // Create tmpost channel required by OrderRepository
    if (Channel::where('slug', 'tmpost')->doesntExist()) {
        Channel::create(['slug' => 'tmpost', 'name' => 'TM Post']);
    }

    // Mock default payment type for OrderPayment::default()
    if (PaymentType::count() === 0) {
        $paymentType = new PaymentType;
        $paymentType->forceFill([
            'id' => 1,
            'code' => 'cash',
            'name' => ['en' => 'Cash'],
            'tax' => 0,
            'is_enabled' => true,
        ]);
        $paymentType->save();
    }
});

test('authenticated user can list their orders', function () {
    $order = new Order;
    $order->forceFill([
        'user_id' => $this->user->id,
        'number' => 'ORD-123',
        'customer_name' => 'John Doe',
        'customer_phone' => 61929248,
        'customer_address' => 'Test Address',
        'shipping_method' => OrderShipping::STANDART,
        'shipping_price' => 20,
        'payment_type_id' => 1, // Assuming ID 1 exists or mocked
        'region' => Region::AG,
        'delivery_at' => now(),
        'status' => OrderStatus::PENDING,
    ]);
    $order->save();

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

    $response->assertOk()
        ->assertJsonStructure([
            'data' => [
                '*' => [
                    'id',
                    'number',
                    // Add other fields from OrderIndexResource
                ],
            ],
        ]);
});

test('unauthenticated user cannot list orders', function () {
    $this->withHeaders(['Api-Token' => 'test-token'])
        ->getJson('/api/v1/orders')
        ->assertUnauthorized();
});

test('can place an order', function () {
    // Setup prerequisites
    $product = Product::create([
        'name' => 'Test Product',
        'slug' => 'test-product',
        'price_amount' => 100,
        'cost_amount' => 80,
        'stock' => 10,
        'is_visible' => true,
    ]);

    // Add item to cart
    CartItem::create([
        'user_id' => $this->user->id,
        'product_id' => $product->id,
        'product_quantity' => 2,
    ]);

    // Mock PaymentType if needed (OrderPayment::values() uses DB)
    PaymentType::create([
        'code' => 'card',
        'name' => ['en' => 'Card'],
        'tax' => 0,
        'is_enabled' => true,
    ]);
    $paymentTypeId = PaymentType::where('code', 'card')->first()->id;

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => 'test-token'])
        ->postJson('/api/v1/orders', [
            'customer_name' => 'John Doe',
            'customer_phone' => 61929248,
            'customer_address' => '123 Main St',
            'shipping_method' => OrderShipping::STANDART,
            'payment_type_id' => $paymentTypeId,
            'region' => Region::AG,
            'notes' => 'Test order',
        ]);

    $response->assertCreated()
        ->assertJsonStructure(['data' => ['order_id']]);

    // Verify order created
    $this->assertDatabaseHas('orders', [
        'user_id' => $this->user->id,
        'customer_name' => 'John Doe',
        'notes' => 'Test order',
    ]);

    // Verify cart cleared
    $this->assertDatabaseMissing('cart_items', [
        'user_id' => $this->user->id,
    ]);

    // Verify stock reduced
    $this->assertEquals(8, $product->fresh()->stock);
});

test('cannot place order with empty cart', function () {
    // Ensure cart is empty
    $this->user->carts()->delete();

    // Mock PaymentType
    PaymentType::create([
        'code' => 'online', // unique code
        'name' => ['en' => 'Online'],
        'tax' => 0,
        'is_enabled' => true,
    ]);
    $paymentTypeId = PaymentType::where('code', 'online')->first()->id;

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => 'test-token'])
        ->postJson('/api/v1/orders', [
            'customer_name' => 'John Doe',
            'customer_phone' => 61929248,
            'customer_address' => '123 Main St',
            'shipping_method' => OrderShipping::STANDART,
            'payment_type_id' => $paymentTypeId,
            'region' => Region::AG,
        ]);

    // The validation 'user_without_product_in_cart' should fail
    $response->assertStatus(422)
        ->assertJsonValidationErrors(['user_without_product_in_cart']);
});

test('order validation fails with invalid data', function () {
    // Add item to cart to pass that check
    $product = Product::create(['name' => 'P', 'slug' => 'p', 'stock' => 1]);
    CartItem::create(['user_id' => $this->user->id, 'product_id' => $product->id, 'product_quantity' => 1]);

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => 'test-token'])
        ->postJson('/api/v1/orders', [
            'customer_name' => '', // Required
            'shipping_method' => 'invalid_method', // Invalid enum
        ]);

    $response->assertStatus(422)
        ->assertJsonValidationErrors(['customer_name', 'shipping_method']);
});

test('can show specific order', function () {
    $order = new Order;
    $order->forceFill([
        'user_id' => $this->user->id,
        'number' => 'ORD-SHOW',
        'customer_name' => 'John Doe',
        'customer_phone' => 61929248,
        'customer_address' => 'Address',
        'shipping_method' => OrderShipping::STANDART,
        'shipping_price' => 20,
        'payment_type_id' => 1,
        'region' => Region::AG,
        'delivery_at' => now(),
        'status' => OrderStatus::PENDING,
    ]);
    $order->save();

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => 'test-token'])
        ->getJson("/api/v1/orders/{$order->id}");

    $response->assertOk()
        ->assertJsonPath('data.id', $order->id)
        ->assertJsonPath('data.number', 'ORD-SHOW');
});

test('can delete order (if allowed)', function () {
    // Note: The controller destroy method is basically empty: return response()->rest();
    // But the route exists. Let's test it returns 200 at least.

    $order = new Order;
    $order->forceFill([
        'user_id' => $this->user->id,
        'number' => 'ORD-DEL',
        'customer_name' => 'John Doe',
        'customer_phone' => 61929248,
        'customer_address' => 'Address',
        'shipping_method' => OrderShipping::STANDART,
        'shipping_price' => 20,
        'payment_type_id' => 1,
        'region' => Region::AG,
        'delivery_at' => now(),
        'status' => OrderStatus::PENDING,
    ]);
    $order->save();

    $response = $this->actingAs($this->user, 'sanctum')
        ->withHeaders(['Api-Token' => 'test-token'])
        ->deleteJson("/api/v1/orders/{$order->id}");

    $response->assertOk();

    $this->assertSoftDeleted('orders', [
        'id' => $order->id,
    ]);
});
