<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\Category;
use App\Models\Customer;
use App\Models\Order;
use App\Models\Product;
use App\Models\ProductStock;
use App\Models\User;
use App\Services\InventoryService;
use App\Services\OrderService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;

class InventoryAndReportTest extends TestCase
{
    use RefreshDatabase;

    public function test_purchase_opname_and_adjustment_create_stock_mutations(): void
    {
        [$branch, $owner, $product] = $this->fixtures();

        app(InventoryService::class)->purchase([
            'branch_id' => $branch->id,
            'purchase_date' => now()->toDateString(),
            'items' => [
                ['product_id' => $product->id, 'quantity' => 10, 'unit_cost' => 7000],
            ],
        ], $owner);

        $this->assertSame(10.0, (float) ProductStock::query()->where('product_id', $product->id)->first()->quantity);
        $this->assertDatabaseHas('stock_mutations', ['source_type' => 'purchase', 'quantity_change' => 10]);

        app(InventoryService::class)->opname([
            'branch_id' => $branch->id,
            'opname_date' => now()->toDateString(),
            'items' => [
                ['product_id' => $product->id, 'actual_quantity' => 8],
            ],
        ], $owner);

        $this->assertSame(8.0, (float) ProductStock::query()->where('product_id', $product->id)->first()->quantity);
        $this->assertDatabaseHas('stock_mutations', ['source_type' => 'stock_opname', 'quantity_change' => -2]);

        app(InventoryService::class)->adjust([
            'branch_id' => $branch->id,
            'product_id' => $product->id,
            'quantity' => 12,
            'note' => 'Koreksi',
        ], $owner);

        $this->assertSame(12.0, (float) ProductStock::query()->where('product_id', $product->id)->first()->quantity);
        $this->assertDatabaseHas('stock_mutations', ['source_type' => 'stock_adjustment', 'quantity_change' => 4]);
    }

    public function test_report_disburse_bonus_marks_details_and_creates_expense(): void
    {
        [$branch, $owner, , $service, $customer] = $this->fixtures(withService: true);

        $order = app(OrderService::class)->checkout([
            'branch_id' => $branch->id,
            'customer_id' => $customer->id,
            'items' => [
                ['product_id' => $service->id, 'quantity' => 2, 'staff_id' => $owner->id],
            ],
            'paid_amount' => 20000,
        ], $owner);

        $this->assertGreaterThan(0, (float) $order->details()->first()->bonus_amount);

        $this->actingAs($owner)->get(route('reports.index', [
            'branch_id' => $branch->id,
            'start_date' => now()->subDay()->toDateString(),
            'end_date' => now()->addDay()->toDateString(),
        ]))->assertOk()->assertSee('Bonus Karyawan');

        $this->actingAs($owner)->post(route('reports.bonus.disburse'), [
            'branch_id' => $branch->id,
            'start_date' => now()->subDay()->toDateString(),
            'end_date' => now()->addDay()->toDateString(),
        ])->assertRedirect();

        $this->assertNotNull($order->details()->first()->refresh()->bonus_paid_at);
        $this->assertDatabaseHas('operational_expenses', ['type' => 'bonus_payout']);
    }

    private function fixtures(bool $withService = false): array
    {
        $branch = Branch::query()->create(['name' => 'Cabang Inventory', 'code' => 'INV']);
        $owner = User::query()->create([
            'branch_id' => $branch->id,
            'name' => 'Owner',
            'email' => 'owner-inventory@example.test',
            'role' => 'owner',
            'password' => Hash::make('password'),
        ]);
        $retailCategory = Category::query()->create(['name' => 'Retail', 'type' => 'retail']);
        $product = Product::query()->create([
            'category_id' => $retailCategory->id,
            'name' => 'Plastik Laundry',
            'sku' => 'RTL-PLS',
            'type' => 'retail',
            'unit' => 'pcs',
            'price' => 10000,
            'cost_price' => 7000,
            'track_stock' => true,
            'minimum_stock' => 5,
        ]);

        if (! $withService) {
            return [$branch, $owner, $product];
        }

        $serviceCategory = Category::query()->create(['name' => 'Service', 'type' => 'service']);
        $service = Product::query()->create([
            'category_id' => $serviceCategory->id,
            'name' => 'Cuci Lipat',
            'sku' => 'SRV-LPT',
            'type' => 'service',
            'unit' => 'kg',
            'price' => 10000,
            'bonus_type' => 'percent',
            'bonus_value' => 10,
        ]);
        $customer = Customer::query()->create([
            'branch_id' => $branch->id,
            'name' => 'Customer',
            'phone' => '62819990000',
            'pin' => Hash::make('000000'),
        ]);

        return [$branch, $owner, $product, $service, $customer];
    }
}
