<?php

use App\Models\Branch;
use App\Models\Category;
use App\Models\Item;
use App\Models\Kot;
use App\Models\KotItem;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\RestaurantTable;
use App\Models\TableArea;
use App\Models\User;

use function Pest\Laravel\getJson;
use function Pest\Laravel\postJson;

beforeEach(function () {
    // Set up database environment manually to guarantee valid foreign constraint references
    $this->owner = User::factory()->create([
        'role' => 'owner',
    ]);

    $this->branch = Branch::create([
        'user_id' => $this->owner->id,
        'name' => 'Main Street Branch',
        'slug' => 'main-street-branch',
        'address' => '123 Main St',
        'phone' => '1234567890',
        'active' => true,
    ]);

    $this->biller = User::factory()->create([
        'role' => 'biller',
        'active_branch_id' => $this->branch->id,
        'parent_id' => $this->owner->id,
        'active' => 1,
    ]);

    $this->token = $this->biller->createToken('test-token')->plainTextToken;

    // Create a waiter
    $this->waiter = User::factory()->create([
        'role' => 'waiter',
        'active_branch_id' => $this->branch->id,
        'parent_id' => $this->owner->id,
        'active' => 1,
    ]);

    // Create an area
    $this->area = TableArea::create([
        'branch_id' => $this->branch->id,
        'name' => 'Main Hall',
        'is_active' => true,
    ]);

    // Create a table
    $this->table = RestaurantTable::create([
        'branch_id' => $this->branch->id,
        'area_id' => $this->area->id,
        'name' => 'Table 01',
        'capacity' => 4,
        'status' => 'available',
        'pos_x' => 120,
        'pos_y' => 80,
        'width' => 60,
        'height' => 60,
        'shape' => 'square',
        'is_active' => true,
    ]);

    // Create categories & items
    $this->category = Category::create([
        'branch_id' => $this->branch->id,
        'name' => 'Burgers',
        'slug' => 'burgers',
        'is_active' => true,
    ]);

    $this->item = Item::create([
        'branch_id' => $this->branch->id,
        'category_id' => $this->category->id,
        'name' => 'Chicken Burger',
        'slug' => 'chicken-burger',
        'price' => 12.50,
        'dine_in_price' => 12.50,
        'delivery_price' => 14.00,
        'takeaway_price' => 12.50,
        'gst_percentage' => 5.00,
        'tax_inclusive' => true,
        'available_dine_in' => true,
        'available_delivery' => true,
        'available_takeaway' => true,
        'is_active' => true,
    ]);
});

test('order endpoints require authentication', function () {
    getJson(url('api/biller/orders/active'))->assertUnauthorized();
    postJson(url('api/biller/orders/hold'), [])->assertUnauthorized();
    postJson(url('api/biller/orders/kot'), [])->assertUnauthorized();
    postJson(url('api/biller/orders/settle'), [])->assertUnauthorized();
});

test('biller can load active orders only', function () {
    // Create an active order
    $activeOrder = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'active',
        'subtotal' => 25.00,
        'gst_amount' => 1.25,
        'grand_total' => 26.25,
    ]);

    // Create a settled order
    $settledOrder = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'settled',
        'subtotal' => 50.00,
        'gst_amount' => 2.50,
        'grand_total' => 52.50,
    ]);

    $response = getJson(
        url('api/biller/orders/active'),
        ['Authorization' => "Bearer $this->token"]
    );

    $response->assertSuccessful()
        ->assertJsonCount(1)
        ->assertJsonPath('0.id', $activeOrder->id)
        ->assertJsonPath('0.status', 'active');
});

test('biller can hold a new draft order and mark table as occupied', function () {
    $payload = [
        'order_type' => 'dine_in',
        'table_id' => $this->table->id,
        'waiter_id' => $this->waiter->id,
        'customer_name' => 'John Doe',
        'customer_phone' => '9876543210',
        'subtotal' => 25.00,
        'gst_amount' => 1.25,
        'grand_total' => 26.25,
        'cart' => [
            [
                'id' => $this->item->id,
                'name' => 'Chicken Burger',
                'price' => 12.50,
                'qty' => 2,
            ],
        ],
    ];

    $response = postJson(
        url('api/biller/orders/hold'),
        $payload,
        ['Authorization' => "Bearer $this->token"]
    );

    $response->assertSuccessful()
        ->assertJson(['success' => true]);

    $orderId = $response->json('order_id');
    expect($orderId)->not->toBeNull();

    $this->assertDatabaseHas('orders', [
        'id' => $orderId,
        'table_id' => $this->table->id,
        'status' => 'active',
        'grand_total' => 26.25,
    ]);

    $this->assertDatabaseHas('order_items', [
        'order_id' => $orderId,
        'item_id' => $this->item->id,
        'quantity' => 2,
    ]);

    $this->table->refresh();
    expect($this->table->status)->toBe('occupied');
});

test('biller can update held order and sync cart items correctly', function () {
    // Start with a held order with Qty = 2
    $order = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'active',
        'subtotal' => 25.00,
        'gst_amount' => 1.25,
        'grand_total' => 26.25,
    ]);

    $orderItem = OrderItem::create([
        'order_id' => $order->id,
        'item_id' => $this->item->id,
        'name' => 'Chicken Burger',
        'price' => 12.50,
        'quantity' => 2,
        'subtotal' => 25.00,
    ]);

    // Update with Qty = 3 and add another temporary item (which will be removed on next hold sync)
    $payload = [
        'order_id' => $order->id,
        'order_type' => 'dine_in',
        'table_id' => $this->table->id,
        'waiter_id' => $this->waiter->id,
        'subtotal' => 37.50,
        'gst_amount' => 1.88,
        'grand_total' => 39.38,
        'cart' => [
            [
                'id' => $this->item->id,
                'name' => 'Chicken Burger',
                'price' => 12.50,
                'qty' => 3,
            ],
        ],
    ];

    $response = postJson(
        url('api/biller/orders/hold'),
        $payload,
        ['Authorization' => "Bearer $this->token"]
    );

    $response->assertSuccessful();

    $this->assertDatabaseHas('order_items', [
        'id' => $orderItem->id,
        'quantity' => 3,
    ]);
});

test('biller can fire KOT and fire subsequent KOTs with incremental quantities only', function () {
    $payload = [
        'order_type' => 'dine_in',
        'table_id' => $this->table->id,
        'waiter_id' => $this->waiter->id,
        'subtotal' => 25.00,
        'gst_amount' => 1.25,
        'grand_total' => 26.25,
        'cart' => [
            [
                'id' => $this->item->id,
                'name' => 'Chicken Burger',
                'price' => 12.50,
                'qty' => 2,
            ],
        ],
    ];

    // First KOT Fire
    $response1 = postJson(
        url('api/biller/orders/kot'),
        $payload,
        ['Authorization' => "Bearer $this->token"]
    );

    $response1->assertSuccessful();
    $orderId = $response1->json('order_id');
    $kotId1 = $response1->json('kot_id');

    expect($orderId)->not->toBeNull();
    expect($kotId1)->not->toBeNull();

    $this->assertDatabaseHas('kots', [
        'id' => $kotId1,
        'order_id' => $orderId,
    ]);

    $this->assertDatabaseHas('kot_items', [
        'kot_id' => $kotId1,
        'item_id' => $this->item->id,
        'quantity' => 2,
    ]);

    // Update quantity to 5 in the cart and fire KOT again
    $payload['order_id'] = $orderId;
    $payload['cart'][0]['qty'] = 5;
    $payload['subtotal'] = 62.50;
    $payload['gst_amount'] = 3.13;
    $payload['grand_total'] = 65.63;

    $response2 = postJson(
        url('api/biller/orders/kot'),
        $payload,
        ['Authorization' => "Bearer $this->token"]
    );

    $response2->assertSuccessful();
    $kotId2 = $response2->json('kot_id');
    expect($kotId2)->not->toBeNull();
    expect($kotId2)->not->toBe($kotId1);

    // Should only fire the incremental quantity (5 - 2 = 3)
    $this->assertDatabaseHas('kot_items', [
        'kot_id' => $kotId2,
        'item_id' => $this->item->id,
        'quantity' => 3,
    ]);
});

test('biller can settle order payment and release table back to available', function () {
    // Create an occupied table
    $this->table->update(['status' => 'occupied']);

    // Create an active order
    $order = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'active',
        'subtotal' => 50.00,
        'gst_amount' => 2.50,
        'grand_total' => 52.50,
    ]);

    $payload = [
        'order_id' => $order->id,
        'discount_type' => 'percentage',
        'discount_value' => 10.00,
        'discount_amount' => 5.00,
        'grand_total' => 47.50,
        'payment_method' => 'split',
        'split_cash' => 20.00,
        'split_card' => 27.50,
        'split_upi' => 0.00,
    ];

    $response = postJson(
        url('api/biller/orders/settle'),
        $payload,
        ['Authorization' => "Bearer $this->token"]
    );

    $response->assertSuccessful();

    $this->assertDatabaseHas('orders', [
        'id' => $order->id,
        'status' => 'settled',
        'discount_type' => 'percentage',
        'discount_value' => 10.00,
        'discount_amount' => 5.00,
        'grand_total' => 47.50,
        'payment_method' => 'split',
        'split_cash' => 20.00,
        'split_card' => 27.50,
    ]);

    $this->table->refresh();
    expect($this->table->status)->toBe('available');
});

test('biller can fetch transaction logs with default date filtering', function () {
    // Create an order owned by this biller today
    $orderToday = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'settled',
        'subtotal' => 50.00,
        'gst_amount' => 2.50,
        'grand_total' => 52.50,
    ]);
    $orderToday->created_at = now();
    $orderToday->save();

    // Create an order owned by this biller yesterday
    $orderYesterday = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'settled',
        'subtotal' => 30.00,
        'gst_amount' => 1.50,
        'grand_total' => 31.50,
    ]);
    $orderYesterday->created_at = now()->subDay();
    $orderYesterday->save();

    // Default fetch (today)
    $responseDefault = getJson(
        url('api/biller/orders'),
        ['Authorization' => "Bearer $this->token"]
    );

    $responseDefault->assertSuccessful()
        ->assertJsonPath('data.0.id', $orderToday->id);

    // Yesterday fetch
    $responseYesterday = getJson(
        url('api/biller/orders?date_filter=yesterday'),
        ['Authorization' => "Bearer $this->token"]
    );

    $responseYesterday->assertSuccessful()
        ->assertJsonPath('data.0.id', $orderYesterday->id);
});

test('biller can fetch detailed single order details', function () {
    $order = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $this->biller->id,
        'order_type' => 'dine_in',
        'status' => 'settled',
        'subtotal' => 50.00,
        'gst_amount' => 2.50,
        'grand_total' => 52.50,
    ]);

    $response = getJson(
        url("api/biller/orders/{$order->id}"),
        ['Authorization' => "Bearer $this->token"]
    );

    $response->assertSuccessful()
        ->assertJsonPath('id', $order->id)
        ->assertJsonPath('status', 'settled')
        ->assertJsonStructure([
            'id',
            'table',
            'waiter',
            'branch',
            'items',
        ]);
});

test('unauthorized biller cannot view details of order owned by another biller', function () {
    $otherBiller = User::factory()->create([
        'role' => 'biller',
        'active_branch_id' => $this->branch->id,
        'parent_id' => $this->owner->id,
    ]);

    $order = Order::create([
        'branch_id' => $this->branch->id,
        'table_id' => $this->table->id,
        'biller_id' => $otherBiller->id,
        'order_type' => 'dine_in',
        'status' => 'settled',
        'subtotal' => 50.00,
        'gst_amount' => 2.50,
        'grand_total' => 52.50,
    ]);

    $response = getJson(
        url("api/biller/orders/{$order->id}"),
        ['Authorization' => "Bearer $this->token"] // This is our biller's token
    );

    $response->assertStatus(403);
});
