<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\User;
use App\Models\Branch;
use App\Models\RawMaterial;
use App\Models\Product;
use App\Models\ProductRecipe;
use App\Models\Stock;
use App\Models\JournalEntry;

class IntegrationPurchaseToSaleTest extends TestCase
{
    use RefreshDatabase;

    public function test_equity_and_balance_sheet_use_stock_based_modal()
    {
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        $product = Product::create([
            'name' => 'Kopi',
            'category' => 'minuman',
            'purchase_price' => 3000,
            'selling_price' => 5000,
            'branch' => $branch->name,
        ]);

        Stock::create([
            'product_id' => $product->id,
            'branch' => $branch->name,
            'quantity' => 3,
            'unit' => 'Pcs',
        ]);

        $response = $this->actingAs($admin)->get('/laporan/perubahan-modal');
        $response->assertOk();
        $response->assertViewHas('data', function ($data) {
            return $data['modal_awal'] == 15000 && $data['modal_akhir'] == 15000;
        });

        $balanceResponse = $this->actingAs($admin)->get('/laporan/neraca-keuangan');
        $balanceResponse->assertOk();
        $balanceResponse->assertViewHas('data', function ($data) {
            return $data['modal_akhir'] == 15000;
        });
    }

    public function test_sale_creates_journal_entries_and_reports_reflect_sales_data()
    {
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        $product = Product::create([
            'name' => 'Kopi',
            'category' => 'minuman',
            'purchase_price' => 4000,
            'selling_price' => 5000,
            'branch' => $branch->name,
        ]);

        Stock::create([
            'product_id' => $product->id,
            'branch' => $branch->name,
            'quantity' => 2,
            'unit' => 'Pcs',
        ]);

        $response = $this->actingAs($admin)->post('/laporan/penjualan', [
            'date' => now()->toDateString(),
            'product_id' => $product->id,
            'quantity' => 1,
            'total_price' => 5000,
            'branch' => $branch->name,
        ]);

        $response->assertSessionHasNoErrors();
        $this->assertDatabaseCount('journal_entries', 1);
        $this->assertDatabaseHas('journal_entries', ['reference_type' => 'Sale']);

        $pnlResponse = $this->actingAs($admin)->get('/laporan/neraca-laba-rugi');
        $pnlResponse->assertOk();
        $pnlResponse->assertViewHas('dataTotal', function ($data) {
            return $data['penjualan'] == 5000 && $data['pembelian'] == 4000 && $data['laba_kotor'] == 1000;
        });

        $cashFlowResponse = $this->actingAs($admin)->get('/laporan/arus-kas');
        $cashFlowResponse->assertOk();
        $cashFlowResponse->assertViewHas('data', function ($data) {
            return $data['penerimaan_penjualan'] == 5000 && $data['arus_kas_operasi'] == 5000;
        });
    }

    public function test_purchase_creates_raw_material_stock_and_product_stock_then_sale_reduces_stocks()
    {
        // Create branch and user
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        // Create raw material
        $rm = RawMaterial::create(['name' => 'Tepung', 'unit' => 'gram', 'stock_quantity' => 0, 'branch' => $branch->name]);

        // Create product that uses 100 grams per unit
        $product = Product::create([
            'name' => 'Roti',
            'category' => 'makanan',
            'purchase_price' => 1000,
            'selling_price' => 2000,
            'branch' => $branch->name,
        ]);

        ProductRecipe::create([
            'product_id' => $product->id,
            'raw_material_id' => $rm->id,
            'quantity_needed' => 100,
        ]);

        // Ensure no product stock initially
        $this->assertDatabaseMissing('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 1]);

        // Simulate purchase of 1000 grams (1 kilogram)
        $response = $this->actingAs($admin)->post('/laporan/pembelian', [
            'date' => now()->toDateString(),
            'item' => 'Beli Tepung',
            'quantity' => '1000 gram',
            'total_price' => 100000,
            'type' => 'raw_material',
            'raw_material_id' => $rm->id,
            'branch' => $branch->name,
        ]);

        $response->assertSessionHasNoErrors();

        $rm->refresh();
        // 1000 grams purchased
        $this->assertEquals(1000, $rm->stock_quantity);

        // After recalculation, product stock should be floor(1000/100) = 10
        $this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 10]);

        // Simulate sale of 2 units
        $response2 = $this->actingAs($admin)->post('/laporan/penjualan', [
            'date' => now()->toDateString(),
            'product_id' => $product->id,
            'quantity' => 2,
            'total_price' => 4000,
            'branch' => $branch->name,
        ]);

        $response2->assertSessionHasNoErrors();

        $rm->refresh();
        // Raw material should be reduced by 2 * 100 = 200 grams -> remaining 800
        $this->assertEquals(800, $rm->stock_quantity);

        // Product stock recalculated should be floor(800/100) = 8
        $this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 8]);
    }

    public function test_purchase_of_liters_keeps_stock_in_liters()
    {
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        $rm = RawMaterial::create(['name' => 'Air Galon', 'unit' => 'Liter', 'stock_quantity' => 0, 'branch' => $branch->name]);

        $response = $this->actingAs($admin)->post('/laporan/pembelian', [
            'date' => now()->toDateString(),
            'item' => 'Beli Air Galon',
            'quantity' => '30 Liter',
            'total_price' => 300000,
            'type' => 'raw_material',
            'raw_material_id' => $rm->id,
            'branch' => $branch->name,
        ]);

        $response->assertSessionHasNoErrors();

        $rm->refresh();
        $this->assertEquals(30, $rm->stock_quantity);
    }

    public function test_sale_of_es_teh_reduces_tea_and_gallon_raw_materials()
    {
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        $teh = RawMaterial::create(['name' => 'Teh', 'unit' => 'Gram', 'stock_quantity' => 100, 'branch' => $branch->name]);
        $airGalon = RawMaterial::create(['name' => 'Air Galon', 'unit' => 'Liter', 'stock_quantity' => 10, 'branch' => $branch->name]);

        $product = Product::create([
            'name' => 'Es Teh',
            'category' => 'minuman',
            'purchase_price' => 2000,
            'selling_price' => 5000,
            'branch' => $branch->name,
        ]);

        ProductRecipe::create([ 'product_id' => $product->id, 'raw_material_id' => $teh->id, 'quantity_needed' => 10 ]);
        ProductRecipe::create([ 'product_id' => $product->id, 'raw_material_id' => $airGalon->id, 'quantity_needed' => 1 ]);

        Stock::create(['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 10, 'unit' => 'Pcs']);

        $response = $this->actingAs($admin)->post('/laporan/penjualan', [
            'date' => now()->toDateString(),
            'product_id' => $product->id,
            'quantity' => 1,
            'total_price' => 5000,
            'branch' => $branch->name,
        ]);

        $response->assertSessionHasNoErrors();

        $teh->refresh();
        $airGalon->refresh();
        $this->assertEquals(90, $teh->stock_quantity);
        $this->assertEquals(9, $airGalon->stock_quantity);
        $this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 9]);
    }

    public function test_sale_reduces_product_stock_for_recipe_based_product()
    {
        $branch = Branch::create(['name' => 'Cabang 1']);
        $admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);

        $rm = RawMaterial::create(['name' => 'Teh', 'unit' => 'gram', 'stock_quantity' => 200, 'branch' => $branch->name]);
        $product = Product::create([
            'name' => 'Es Teh',
            'category' => 'minuman',
            'purchase_price' => 2000,
            'selling_price' => 5000,
            'branch' => $branch->name,
        ]);

        ProductRecipe::create([
            'product_id' => $product->id,
            'raw_material_id' => $rm->id,
            'quantity_needed' => 20,
        ]);

        Stock::create([
            'product_id' => $product->id,
            'branch' => $branch->name,
            'quantity' => 10,
            'unit' => 'Pcs',
        ]);

        $response = $this->actingAs($admin)->post('/laporan/penjualan', [
            'date' => now()->toDateString(),
            'product_id' => $product->id,
            'quantity' => 1,
            'total_price' => 5000,
            'branch' => $branch->name,
        ]);

        $response->assertSessionHasNoErrors();

        $rm->refresh();
        $this->assertEquals(180, $rm->stock_quantity);
        $this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 9]);
    }
}
