<?php

namespace Tests\Feature;

use App\Models\Customer;
use App\Models\Promotion;
use App\Models\Product;
use App\Models\StockLevel;
use Illuminate\Support\Facades\DB;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class CheckoutApiTest extends TestCase
{
    use RefreshDatabase;

    public function test_checkout_posts_order_payment_and_decrements_stock(): void
    {
        ['company' => $company, 'user' => $user, 'branch' => $branch] = $this->createUserWithPermissions([
            'shifts.manage',
            'orders.view',
            'orders.manage',
            'payments.manage',
        ]);

        $paymentMethod = $this->createPaymentMethod($company);

        $product = Product::factory()->create([
            'company_id' => $company->id,
            'name' => 'Bread',
            'sku' => 'BREAD01',
            'cost_price' => 40,
            'selling_price' => 70,
        ]);

        StockLevel::create([
            'branch_id' => $branch->id,
            'product_id' => $product->id,
            'quantity' => 10,
            'reserved_quantity' => 0,
        ]);

        $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/shifts/open', [
                'opening_float' => 200,
            ])
            ->assertCreated();

        $payload = [
            'device_id' => 'tablet-1',
            'local_id' => 'uuid-1',
            'items' => [
                [
                    'product_id' => $product->id,
                    'quantity' => 3,
                ],
            ],
            'payments' => [
                [
                    'payment_method_id' => $paymentMethod->id,
                    'amount' => 210,
                ],
            ],
        ];

        $order = $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/orders', $payload);

        $order->assertCreated()
            ->assertJsonPath('data.status', 'completed')
            ->assertJsonPath('data.total_amount', '210.0000');

        $duplicate = $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/orders', $payload);

        $duplicate->assertOk()
            ->assertJsonPath('data.id', $order->json('data.id'));

        $stock = StockLevel::query()
            ->where('branch_id', $branch->id)
            ->where('product_id', $product->id)
            ->firstOrFail();

        $this->assertSame('7.0000', $stock->quantity);
    }

    public function test_checkout_applies_supported_promotion_discount(): void
    {
        ['company' => $company, 'user' => $user, 'branch' => $branch] = $this->createUserWithPermissions([
            'shifts.manage',
            'orders.manage',
            'payments.manage',
        ]);

        $paymentMethod = $this->createPaymentMethod($company);
        $product = Product::factory()->create([
            'company_id' => $company->id,
            'selling_price' => 100,
            'cost_price' => 60,
        ]);

        $promotion = Promotion::create([
            'company_id' => $company->id,
            'name' => 'Ten Percent Off',
            'code' => 'TENOFF',
            'type' => 'percentage',
            'discount_value' => 10,
            'applies_to' => 'all',
            'starts_at' => now()->subDay(),
            'ends_at' => now()->addDay(),
            'is_active' => true,
        ]);

        StockLevel::create([
            'branch_id' => $branch->id,
            'product_id' => $product->id,
            'quantity' => 20,
            'reserved_quantity' => 0,
        ]);

        $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/shifts/open', [])
            ->assertCreated();

        $response = $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/orders', [
                'promotion_id' => $promotion->id,
                'items' => [
                    [
                        'product_id' => $product->id,
                        'quantity' => 2,
                    ],
                ],
                'payments' => [
                    [
                        'payment_method_id' => $paymentMethod->id,
                        'amount' => 180,
                    ],
                ],
            ]);

        $response->assertCreated()
            ->assertJsonPath('data.discount_amount', '20.0000')
            ->assertJsonPath('data.total_amount', '180.0000');

        $this->assertDatabaseHas('promotions', [
            'id' => $promotion->id,
            'usage_count' => 1,
        ]);
    }

    public function test_checkout_redeems_and_earns_loyalty_points_for_customer(): void
    {
        ['company' => $company, 'user' => $user, 'branch' => $branch] = $this->createUserWithPermissions([
            'shifts.manage',
            'orders.manage',
            'payments.manage',
        ]);

        $paymentMethod = $this->createPaymentMethod($company);
        $customer = Customer::factory()->create([
            'company_id' => $company->id,
            'loyalty_points' => 50,
            'total_purchases' => 0,
        ]);
        $product = Product::factory()->create([
            'company_id' => $company->id,
            'selling_price' => 200,
            'cost_price' => 100,
        ]);

        StockLevel::create([
            'branch_id' => $branch->id,
            'product_id' => $product->id,
            'quantity' => 10,
            'reserved_quantity' => 0,
        ]);

        $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/shifts/open', [])
            ->assertCreated();

        $response = $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/orders', [
                'customer_id' => $customer->id,
                'loyalty_points_to_redeem' => 20,
                'items' => [
                    [
                        'product_id' => $product->id,
                        'quantity' => 2,
                    ],
                ],
                'payments' => [
                    [
                        'payment_method_id' => $paymentMethod->id,
                        'amount' => 380,
                    ],
                ],
            ]);

        $response->assertCreated()
            ->assertJsonPath('data.total_amount', '380.0000')
            ->assertJsonPath('data.loyalty_points_redeemed', 20)
            ->assertJsonPath('data.loyalty_points_earned', 3);

        $customer->refresh();
        $this->assertSame(33, $customer->loyalty_points);
        $this->assertSame('380.00', $customer->total_purchases);

        $this->assertDatabaseHas('loyalty_transactions', [
            'customer_id' => $customer->id,
            'type' => 'redeemed',
            'points' => -20,
        ]);

        $this->assertDatabaseHas('loyalty_transactions', [
            'customer_id' => $customer->id,
            'type' => 'earned',
            'points' => 3,
        ]);
    }

    public function test_checkout_rejects_unsupported_promotion_types(): void
    {
        ['company' => $company, 'user' => $user, 'branch' => $branch] = $this->createUserWithPermissions([
            'shifts.manage',
            'orders.manage',
            'payments.manage',
        ]);

        $paymentMethod = $this->createPaymentMethod($company);
        $product = Product::factory()->create([
            'company_id' => $company->id,
            'selling_price' => 100,
        ]);

        $promotion = Promotion::create([
            'company_id' => $company->id,
            'name' => 'BOGO',
            'code' => 'BOGO',
            'type' => 'buy_x_get_y',
            'discount_value' => 0,
            'applies_to' => 'all',
            'starts_at' => now()->subDay(),
            'ends_at' => now()->addDay(),
            'is_active' => true,
        ]);

        StockLevel::create([
            'branch_id' => $branch->id,
            'product_id' => $product->id,
            'quantity' => 10,
            'reserved_quantity' => 0,
        ]);

        $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/shifts/open', [])
            ->assertCreated();

        $response = $this->actingAsApi($user, $branch->id)
            ->postJson('/api/v1/orders', [
                'promotion_id' => $promotion->id,
                'items' => [
                    [
                        'product_id' => $product->id,
                        'quantity' => 1,
                    ],
                ],
                'payments' => [
                    [
                        'payment_method_id' => $paymentMethod->id,
                        'amount' => 100,
                    ],
                ],
            ]);

        $response->assertUnprocessable()
            ->assertJsonPath('errors.promotion_id.0', 'The selected promotion type is not supported at checkout yet.');
    }
}
