<?php

use App\Models\User;
use App\Models\Outlet;
use App\Models\Table;
use App\Models\Customer;
use App\Models\Ingredient;
use App\Models\OutletIngredient;
use App\Models\StockOpname;
use App\Models\StockOpnameItem;
use App\Models\Waste;
use App\Models\Transaction;
use App\Models\TransactionItem;
use App\Models\Product;
use App\Models\Modifier;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Role;

uses(RefreshDatabase::class);

beforeEach(function () {
    // Setup essential roles & permissions
    $this->artisan('db:seed', ['--class' => 'RolesAndPermissionsSeeder']);
    $this->artisan('db:seed', ['--class' => 'SettingSeeder']);

    $this->user = User::factory()->create();
    $this->user->assignRole('Super Admin');

    $this->outlet = Outlet::create([
        'name' => 'Test Outlet',
        'location' => 'Jakarta',
    ]);
});

it('can CRUD and merge/split tables', function () {
    $this->actingAs($this->user);

    // 1. Create table
    $response = $this->post(route('tables.store'), [
        'outlet_id' => $this->outlet->id,
        'number' => 'Meja 1',
        'capacity' => 4,
        'status' => 'available',
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('tables', ['number' => 'Meja 1', 'capacity' => 4]);

    $table1 = Table::where('number', 'Meja 1')->first();

    // 2. Create another table
    $this->post(route('tables.store'), [
        'outlet_id' => $this->outlet->id,
        'number' => 'Meja 2',
        'capacity' => 2,
        'status' => 'available',
    ]);
    $table2 = Table::where('number', 'Meja 2')->first();

    // 3. Merge table 2 into table 1
    $response = $this->post(route('tables.merge'), [
        'source_table_id' => $table2->id,
        'target_table_id' => $table1->id,
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('tables', [
        'id' => $table2->id,
        'merged_to_id' => $table1->id,
        'status' => 'occupied',
    ]);

    // 4. Split table
    $response = $this->post(route('tables.split'), [
        'table_id' => $table2->id,
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('tables', [
        'id' => $table2->id,
        'merged_to_id' => null,
        'status' => 'available',
    ]);
});

it('can manage customers and accumulate loyalty points', function () {
    $this->actingAs($this->user);

    // 1. Create customer
    $response = $this->post(route('customers.store'), [
        'name' => 'Charlie member',
        'phone' => '081234567890',
        'email' => 'charlie@member.com',
        'is_member' => true,
        'loyalty_points' => 50,
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('customers', [
        'name' => 'Charlie member',
        'loyalty_points' => 50,
    ]);

    $customer = Customer::where('name', 'Charlie member')->first();

    // 2. Update customer details
    $response = $this->put(route('customers.update', $customer->id), [
        'name' => 'Charlie Member Updated',
        'phone' => '081234567890',
        'email' => 'charlie@member.com',
        'is_member' => true,
        'loyalty_points' => 80,
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('customers', [
        'id' => $customer->id,
        'name' => 'Charlie Member Updated',
        'loyalty_points' => 80,
    ]);
});

it('can create and finalize a stock opname audit', function () {
    $this->actingAs($this->user);

    // Create ingredient & record stock qty
    $ingredient = Ingredient::create(['name' => 'Kopi Arabika', 'unit' => 'g']);
    $outletIng = OutletIngredient::create([
        'outlet_id' => $this->outlet->id,
        'ingredient_id' => $ingredient->id,
        'stock_qty' => 500,
        'threshold_qty' => 100,
    ]);

    // 1. Start stock opname draft
    $response = $this->post(route('opnames.store'), [
        'outlet_id' => $this->outlet->id,
    ]);
    $response->assertRedirect();
    $this->assertDatabaseHas('stock_opnames', ['outlet_id' => $this->outlet->id, 'status' => 'draft']);

    $opname = StockOpname::where('outlet_id', $this->outlet->id)->first();
    $opnameItem = StockOpnameItem::where('stock_opname_id', $opname->id)->first();

    // 2. Complete/Finalize audit with actual physical stock input (e.g. 480g instead of 500g)
    $response = $this->post(route('opnames.complete', $opname->id), [
        'items' => [
            [
                'id' => $opnameItem->id,
                'actual_qty' => 480,
            ]
        ]
    ]);
    $response->assertRedirect();

    $this->assertDatabaseHas('stock_opnames', ['id' => $opname->id, 'status' => 'completed']);
    $this->assertDatabaseHas('stock_opname_items', [
        'id' => $opnameItem->id,
        'actual_qty' => 480,
        'difference_qty' => -20,
    ]);

    // Check inventory stock is corrected
    $this->assertEquals(480, OutletIngredient::where('outlet_id', $this->outlet->id)->where('ingredient_id', $ingredient->id)->value('stock_qty'));
});

it('can record stock wastes and reduce stock levels', function () {
    $this->actingAs($this->user);

    $ingredient = Ingredient::create(['name' => 'Susu Segar', 'unit' => 'ml']);
    $outletIng = OutletIngredient::create([
        'outlet_id' => $this->outlet->id,
        'ingredient_id' => $ingredient->id,
        'stock_qty' => 1000,
        'threshold_qty' => 100,
    ]);

    // Record waste of 250ml due to spoilage
    $response = $this->post(route('wastes.store'), [
        'outlet_id' => $this->outlet->id,
        'item_type' => 'Ingredient',
        'item_id' => $ingredient->id,
        'qty' => 250,
        'notes' => 'Susu pecah / basi',
    ]);

    $response->assertRedirect();
    $this->assertDatabaseHas('wastes', [
        'outlet_id' => $this->outlet->id,
        'item_type' => 'Ingredient',
        'item_id' => $ingredient->id,
        'qty' => 250,
    ]);

    // Check inventory stock is reduced
    $this->assertEquals(750, OutletIngredient::where('outlet_id', $this->outlet->id)->where('ingredient_id', $ingredient->id)->value('stock_qty'));
});

it('can update KDS item status', function () {
    $this->actingAs($this->user);

    $product = Product::create(['name' => 'Iced Cafe Latte', 'price' => 25000, 'category' => 'Coffee']);
    $transaction = Transaction::create([
        'transaction_number' => 'TXN-TEST',
        'outlet_id' => $this->outlet->id,
        'user_id' => $this->user->id,
        'total_amount' => 25000,
        'tax_amount' => 0,
        'service_charge_amount' => 0,
        'payment_method' => 'cash',
        'status' => 'success',
    ]);

    $item = TransactionItem::create([
        'transaction_id' => $transaction->id,
        'product_id' => $product->id,
        'qty' => 1,
        'variant' => 'ice',
        'price' => 25000,
        'subtotal' => 25000,
        'kitchen_status' => 'pending',
    ]);

    // Advance status to cooking
    $response = $this->post(route('kds.items.status', $item->id), ['status' => 'cooking']);
    $response->assertRedirect();
    $this->assertEquals('cooking', $item->fresh()->kitchen_status);

    // Advance status to ready
    $this->post(route('kds.items.status', $item->id), ['status' => 'ready']);
    $this->assertEquals('ready', $item->fresh()->kitchen_status);
});
