<?php

use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\RawMaterial;
use App\Models\RawMaterialPrice;
use App\Models\Supplier;
use App\Models\User;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;

uses(RefreshDatabase::class);

/*
|--------------------------------------------------------------------------
| HELPERS
|--------------------------------------------------------------------------
*/

function givePurchasePermissions(User $user): void
{
    $seeder = new RolePermissionSeeder;
    $seeder->run();

    $user->givePermissionTo([
        'purchase.view',
        'purchase.create',
        'purchase.update',
        'purchase.delete',
    ]);
}

function makeValidPurchasePayload(array $overrides = []): array
{
    return array_merge([
        'name' => 'Bahan Baku Test',
        'unit' => 'kg',
        'variants' => [
            [
                'variant' => 'Varian Default',
                'price' => 50000,
                'stock' => 10,
                'photo_key' => 'raw-material-variant/test-photo.jpg',
            ],
        ],
        'supplier_id' => Supplier::factory()->create()->id,
        'discount' => 0,
        'shipping_cost' => 0,
        'notes' => 'Belanja test',
        'photo_key' => null,
    ], $overrides);
}

/*
|--------------------------------------------------------------------------
| AUTHENTICATION
|--------------------------------------------------------------------------
*/

test('guests are redirected to the login page', function () {
    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertRedirect(route('login'));
});

test('guests are redirected when visiting create page', function () {
    $response = $this->get(route('admin.manage.purchases.create'));
    $response->assertRedirect(route('login'));
});

test('guests are redirected when visiting edit page', function () {
    $purchase = Purchase::factory()->create();
    $response = $this->get(route('admin.manage.purchases.edit', $purchase));
    $response->assertRedirect(route('login'));
});

test('guest cannot create purchase', function () {
    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());
    $response->assertRedirect(route('login'));
    $this->assertDatabaseCount('purchases', 0);
});

test('guest cannot update purchase', function () {
    $purchase = Purchase::factory()->create();
    $response = $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload());
    $response->assertRedirect(route('login'));
});

test('guest cannot delete purchase', function () {
    $purchase = Purchase::factory()->create();
    $response = $this->delete(route('admin.manage.purchases.destroy', $purchase));
    $response->assertRedirect(route('login'));
    $this->assertDatabaseHas('purchases', ['id' => $purchase->id, 'deleted_at' => null]);
});

test('authenticated users can visit the purchase index page', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
});

test('authenticated users can visit the purchase create page', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->get(route('admin.manage.purchases.create'));
    $response->assertOk();
});

test('authenticated users can visit the purchase edit page', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $purchase = Purchase::factory()->create();

    $response = $this->get(route('admin.manage.purchases.edit', $purchase));
    $response->assertOk();
});

/*
|--------------------------------------------------------------------------
| INDEX PAGE
|--------------------------------------------------------------------------
*/

test('purchase index page displays purchases', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    Purchase::factory()->count(3)->create();

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/manage/purchase/index')
        ->has('purchases.data', 3)
        ->where('purchases.total', 3)
        ->where('purchases.current_page', 1)
        ->where('purchases.per_page', 25)
    );
});

test('index page works with zero purchases', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/manage/purchase/index')
        ->has('purchases.data', 0)
        ->where('purchases.total', 0)
    );
});

test('index page does not display soft-deleted purchases', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    Purchase::factory()->create(['notes' => 'Active Purchase']);
    Purchase::factory()->create(['notes' => 'Deleted Purchase'])->delete();

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/manage/purchase/index')
        ->has('purchases.data', 1)
        ->where('purchases.total', 1)
    );
});

test('index page includes purchase items with nested data', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->has('purchases.data.0.purchase_items', 1)
        ->has('purchases.data.0.purchase_items.0.raw_material_price')
        ->has('purchases.data.0.purchase_items.0.raw_material_price.raw_material')
    );
});

test('index page returns correct purchase item data', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
        ],
    ]));

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('purchases.data.0.purchase_items.0.unit_price', 50000)
        ->where('purchases.data.0.purchase_items.0.quantity', 10)
        ->where('purchases.data.0.purchase_items.0.subtotal', 500000)
        ->where('purchases.data.0.purchase_items.0.raw_material_price.variant', 'Merah')
        ->where('purchases.data.0.purchase_items.0.raw_material_price.raw_material.name', 'Bahan Baku Test')
        ->where('purchases.data.0.purchase_items.0.raw_material_price.raw_material.unit', 'kg')
    );
});

test('index page returns multiple purchase items', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
        ],
    ]));

    $response = $this->get(route('admin.manage.purchases.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->has('purchases.data.0.purchase_items', 2)
        ->where('purchases.data.0.purchase_items.0.raw_material_price.variant', 'Merah')
        ->where('purchases.data.0.purchase_items.1.raw_material_price.variant', 'Biru')
    );
});

/*
|--------------------------------------------------------------------------
| CREATE / STORE - BASIC
|--------------------------------------------------------------------------
*/

test('purchase can be created', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());
    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.manage.purchases.index'));

    $this->assertDatabaseCount('purchases', 1);
    $this->assertDatabaseCount('raw_materials', 1);
    $this->assertDatabaseCount('raw_material_prices', 1);
    $this->assertDatabaseCount('purchase_items', 1);
});

test('purchase creates raw material with correct data', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'name' => 'Kain Katun',
        'unit' => 'meter',
    ]));

    $this->assertDatabaseHas('raw_materials', [
        'name' => 'Kain Katun',
        'unit' => 'meter',
        'is_active' => true,
    ]);
});

test('purchase creates raw material variants', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
        ],
    ]));

    $this->assertDatabaseCount('raw_material_prices', 2);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Merah', 'price' => 50000, 'stock' => 10]);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Biru', 'price' => 60000, 'stock' => 5]);
});

test('purchase calculates correct subtotal and total', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
        'discount' => 10000,
        'shipping_cost' => 5000,
    ]));

    $purchase = Purchase::first();
    expect($purchase->subtotal)->toBe(500000);
    expect($purchase->discount)->toBe(10000);
    expect($purchase->shipping_cost)->toBe(5000);
    expect($purchase->total)->toBe(495000);
});

test('purchase sets created_by_id to current user', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();
    expect($purchase->created_by_id)->toBe($user->id);
});

test('purchase can be created with notes', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'notes' => 'Belanja bahan baku untuk produksi',
    ]));

    $purchase = Purchase::first();
    expect($purchase->notes)->toBe('Belanja bahan baku untuk produksi');
});

test('purchase can be created without notes', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'notes' => null,
    ]));

    $purchase = Purchase::first();
    expect($purchase->notes)->toBeNull();
});

test('multiple purchases can be created sequentially', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['name' => 'Bahan 1']));
    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['name' => 'Bahan 2']));
    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['name' => 'Bahan 3']));

    $this->assertDatabaseCount('purchases', 3);
    $this->assertDatabaseCount('raw_materials', 3);
});

test('purchase creates purchase items with correct relationships', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();
    $item = PurchaseItem::first();

    expect($item->purchase_id)->toBe($purchase->id);
    expect($item->raw_material_price_id)->not->toBeNull();
    expect($item->quantity)->toBe(10);
    expect($item->unit_price)->toBe(50000);
    expect($item->subtotal)->toBe(500000);
});

test('purchase item links to correct raw material price', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
        ],
    ]));

    $item = PurchaseItem::first();
    $price = RawMaterialPrice::find($item->raw_material_price_id);

    expect($price)->not->toBeNull();
    expect($price->variant)->toBe('Merah');
    expect($price->price)->toBe(50000);
    expect($price->stock)->toBe(10);
});

test('purchase calculates multiple variant subtotals correctly', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
        ],
        'discount' => 10000,
        'shipping_cost' => 5000,
    ]));

    $purchase = Purchase::first();
    expect($purchase->subtotal)->toBe(800000); // (50000*10) + (60000*5)
    expect($purchase->total)->toBe(795000); // 800000 - 10000 + 5000
});

test('purchase can be created from existing raw material', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $price = RawMaterialPrice::factory()->create(['stock' => 100]);
    $materialId = RawMaterial::first()->id;

    $response = $this->post(route('admin.manage.purchases.store'), [
        'mode' => 'existing',
        'existing_items' => [
            ['raw_material_price_id' => $price->id, 'quantity' => 5, 'unit_price' => 50000],
        ],
        'supplier_id' => Supplier::factory()->create()->id,
        'discount' => 0,
        'shipping_cost' => 0,
        'notes' => null,
        'photo_key' => null,
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.manage.purchases.index'));

    $this->assertDatabaseCount('raw_materials', 1);
    $this->assertDatabaseHas('raw_materials', ['id' => $materialId, 'deleted_at' => null]);
    expect((float) $price->fresh()->stock)->toBe(105.0);
    expect(PurchaseItem::count())->toBe(1);
    expect(PurchaseItem::first()->raw_material_price_id)->toBe($price->id);
});

/*
|--------------------------------------------------------------------------
| STORE VALIDATION - REQUIRED FIELDS
|--------------------------------------------------------------------------
*/

test('purchase name is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['name' => '']));
    $response->assertSessionHasErrors('name');
});

test('purchase unit is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['unit' => '']));
    $response->assertSessionHasErrors('unit');
});

test('purchase variants is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['variants' => []]));
    $response->assertSessionHasErrors('variants');
});

test('purchase variant name is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $payload = makeValidPurchasePayload();
    $payload['variants'][0]['variant'] = '';

    $response = $this->post(route('admin.manage.purchases.store'), $payload);
    $response->assertSessionHasErrors('variants.0.variant');
});

test('purchase variant price is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $payload = makeValidPurchasePayload();
    unset($payload['variants'][0]['price']);

    $response = $this->post(route('admin.manage.purchases.store'), $payload);
    $response->assertSessionHasErrors('variants.0.price');
});

test('purchase variant stock is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $payload = makeValidPurchasePayload();
    unset($payload['variants'][0]['stock']);

    $response = $this->post(route('admin.manage.purchases.store'), $payload);
    $response->assertSessionHasErrors('variants.0.stock');
});

test('purchase variant photo_key is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $payload = makeValidPurchasePayload();
    unset($payload['variants'][0]['photo_key']);

    $response = $this->post(route('admin.manage.purchases.store'), $payload);
    $response->assertSessionHasErrors('variants.0.photo_key');
});

test('purchase supplier_id is required', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['supplier_id' => '']));
    $response->assertSessionHasErrors('supplier_id');
});

test('purchase discount must be >= 0', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['discount' => -100]));
    $response->assertSessionHasErrors('discount');
});

test('purchase shipping_cost must be >= 0', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['shipping_cost' => -100]));
    $response->assertSessionHasErrors('shipping_cost');
});

test('purchase notes must not exceed 100 characters', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload(['notes' => str_repeat('a', 101)]));
    $response->assertSessionHasErrors('notes');
});

/*
|--------------------------------------------------------------------------
| EDIT PAGE
|--------------------------------------------------------------------------
*/

test('edit page shows purchase data', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $purchase = Purchase::factory()->create([
        'discount' => 10000,
        'shipping_cost' => 5000,
        'notes' => 'Test notes',
    ]);

    $rawMaterial = RawMaterial::factory()->create(['name' => 'Kain Test']);
    $variant = RawMaterialPrice::factory()->create([
        'raw_material_id' => $rawMaterial->id,
        'variant' => 'Merah',
        'price' => 50000,
        'stock' => 10,
    ]);
    PurchaseItem::factory()->create([
        'purchase_id' => $purchase->id,
        'raw_material_price_id' => $variant->id,
        'quantity' => 10,
        'unit_price' => 50000,
        'subtotal' => 500000,
    ]);

    $response = $this->get(route('admin.manage.purchases.edit', $purchase));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/manage/purchase/edit')
        ->where('purchase.id', $purchase->id)
        ->where('purchase.name', 'Kain Test')
        ->has('purchase.unit')
        ->has('purchase.variants', 1)
        ->has('data.suppliers')
    );
});

test('edit page returns suppliers list', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    Supplier::factory()->count(3)->create();

    $purchase = Purchase::factory()->create();

    $response = $this->get(route('admin.manage.purchases.edit', $purchase));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->has('data.suppliers', 4)
    );
});

/*
|--------------------------------------------------------------------------
| UPDATE / PUT
|--------------------------------------------------------------------------
*/

test('purchase can be updated', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();

    $response = $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'name' => 'Bahan Updated',
        'unit' => 'meter',
        'discount' => 20000,
        'shipping_cost' => 10000,
        'notes' => 'Updated notes',
    ]));

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect();

    $purchase->refresh();
    expect($purchase->discount)->toBe(20000);
    expect($purchase->shipping_cost)->toBe(10000);
    expect($purchase->notes)->toBe('Updated notes');
});

test('purchase update recalculates totals', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
        'discount' => 10000,
        'shipping_cost' => 5000,
    ]));

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 60000, 'stock' => 20, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
        'discount' => 20000,
        'shipping_cost' => 10000,
    ]));

    $purchase->refresh();
    expect($purchase->subtotal)->toBe(1200000);
    expect($purchase->discount)->toBe(20000);
    expect($purchase->shipping_cost)->toBe(10000);
    expect($purchase->total)->toBe(1190000);
});

test('purchase update reuses the same raw material in place', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'name' => 'Old Material',
        'variants' => [
            ['variant' => 'Old Variant', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/old.jpg'],
        ],
    ]));

    $oldRawMaterialId = RawMaterial::where('name', 'Old Material')->first()->id;

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'name' => 'New Material',
        'variants' => [
            ['variant' => 'New Variant', 'price' => 60000, 'stock' => 20, 'photo_key' => 'raw-material-variant/new.jpg'],
        ],
    ]));

    $this->assertDatabaseCount('raw_materials', 1);
    $this->assertDatabaseHas('raw_materials', ['id' => $oldRawMaterialId, 'name' => 'New Material']);
});

test('purchase update never deletes removed variants, only their stock', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'name' => 'Bahan Baku Test',
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
        ],
    ]));

    $price = RawMaterialPrice::where('variant', 'Merah')->first();
    $materialId = RawMaterial::first()->id;

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'name' => 'Bahan Baku Test',
        'variants' => [
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
            ['variant' => 'Hijau', 'price' => 70000, 'stock' => 3, 'photo_key' => 'raw-material-variant/green.jpg'],
        ],
    ]));

    expect(PurchaseItem::count())->toBe(2);
    $this->assertDatabaseCount('raw_material_prices', 3);
    $this->assertDatabaseHas('raw_material_prices', ['raw_material_id' => $materialId, 'variant' => 'Merah', 'stock' => 0]);
    $this->assertDatabaseHas('raw_material_prices', ['raw_material_id' => $materialId, 'variant' => 'Biru', 'stock' => 5]);
    $this->assertDatabaseHas('raw_material_prices', ['raw_material_id' => $materialId, 'variant' => 'Hijau', 'stock' => 3]);
    expect($price->fresh()->trashed())->toBeFalse();
});

test('purchase update adds new variants to the same raw material', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
        ],
    ]));

    $materialId = RawMaterial::first()->id;

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Hijau', 'price' => 70000, 'stock' => 3, 'photo_key' => 'raw-material-variant/green.jpg'],
        ],
    ]));

    $this->assertDatabaseCount('raw_materials', 1);
    $this->assertDatabaseHas('raw_material_prices', ['raw_material_id' => $materialId, 'variant' => 'Hijau', 'stock' => 3]);
    $this->assertDatabaseHas('raw_material_prices', ['raw_material_id' => $materialId, 'variant' => 'Merah', 'stock' => 10]);
    expect(PurchaseItem::count())->toBe(2);
});

test('purchase update adjusts stock by difference', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
    ]));

    $price = RawMaterialPrice::first();
    expect((float) $price->stock)->toBe(10.0);

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 4, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
    ]));

    expect((float) $price->fresh()->stock)->toBe(4.0);
});

test('purchase update in existing mode adjusts stock by difference', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/v1.jpg'],
        ],
    ]));

    $price = RawMaterialPrice::first();
    $purchase = Purchase::first();

    $response = $this->put(route('admin.manage.purchases.update', $purchase), [
        'mode' => 'existing',
        'existing_items' => [
            ['raw_material_price_id' => $price->id, 'quantity' => 4, 'unit_price' => 50000],
        ],
        'supplier_id' => $purchase->supplier_id,
        'discount' => 0,
        'shipping_cost' => 0,
        'notes' => null,
        'photo_key' => null,
    ]);

    $response->assertSessionHasNoErrors();
    expect((float) $price->fresh()->stock)->toBe(4.0);
    expect(PurchaseItem::count())->toBe(1);
});

test('purchase update does not change the raw material unit', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'unit' => 'kg',
    ]));

    $materialId = RawMaterial::first()->id;
    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'unit' => 'meter',
    ]));

    $this->assertDatabaseHas('raw_materials', ['id' => $materialId, 'unit' => 'kg']);
});

test('purchase update replaces old purchase items', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
        ],
    ]));

    $oldItemCount = PurchaseItem::count();

    $purchase = Purchase::first();

    $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
            ['variant' => 'Hijau', 'price' => 70000, 'stock' => 3, 'photo_key' => 'raw-material-variant/green.jpg'],
        ],
    ]));

    expect(PurchaseItem::count())->toBe(2);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Biru']);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Hijau']);
});

test('updating non-existent purchase returns 404', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->put(route('admin.manage.purchases.update', 999999), makeValidPurchasePayload());
    $response->assertStatus(404);
});

/*
|--------------------------------------------------------------------------
| DELETE / DESTROY
|--------------------------------------------------------------------------
*/

test('purchase can be deleted and reduces raw material stock', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();
    $price = RawMaterialPrice::where('variant', 'Varian Default')->first();
    expect((float) $price->stock)->toBe(10.0);

    $response = $this->delete(route('admin.manage.purchases.destroy', $purchase));

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.manage.purchases.index'));

    $this->assertSoftDeleted('purchases', ['id' => $purchase->id]);
    $this->assertDatabaseHas('raw_materials', ['name' => 'Bahan Baku Test', 'deleted_at' => null]);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Varian Default', 'stock' => 0, 'deleted_at' => null]);
});

test('purchase is soft-deleted not permanently removed', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();

    $this->delete(route('admin.manage.purchases.destroy', $purchase));

    $this->assertDatabaseHas('purchases', ['id' => $purchase->id]);
    $this->assertSoftDeleted('purchases', ['id' => $purchase->id]);
});

test('delete cascades to purchase items', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
        ],
    ]));

    $purchase = Purchase::first();
    expect(PurchaseItem::count())->toBe(2);

    $this->delete(route('admin.manage.purchases.destroy', $purchase));

    expect(PurchaseItem::where('purchase_id', $purchase->id)->count())->toBe(0);
});

test('delete reduces stock but keeps raw materials and variants', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload([
        'variants' => [
            ['variant' => 'Merah', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/red.jpg'],
            ['variant' => 'Biru', 'price' => 60000, 'stock' => 5, 'photo_key' => 'raw-material-variant/blue.jpg'],
        ],
    ]));

    $purchase = Purchase::first();
    $rawMaterial = RawMaterial::first();

    $this->delete(route('admin.manage.purchases.destroy', $purchase));

    $this->assertDatabaseHas('raw_materials', ['id' => $rawMaterial->id, 'deleted_at' => null]);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Merah', 'stock' => 0, 'deleted_at' => null]);
    $this->assertDatabaseHas('raw_material_prices', ['variant' => 'Biru', 'stock' => 0, 'deleted_at' => null]);
});

test('deleting non-existent purchase returns 404', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $response = $this->delete(route('admin.manage.purchases.destroy', 999999));
    $response->assertStatus(404);
});

test('updating soft-deleted purchase via route returns 404', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();
    $purchase->delete();

    $response = $this->put(route('admin.manage.purchases.update', $purchase), makeValidPurchasePayload());
    $response->assertStatus(404);
});

test('deleting soft-deleted purchase via route returns 404', function () {
    $user = User::factory()->create();
    givePurchasePermissions($user);
    $this->actingAs($user);

    $this->post(route('admin.manage.purchases.store'), makeValidPurchasePayload());

    $purchase = Purchase::first();
    $purchase->delete();

    $response = $this->delete(route('admin.manage.purchases.destroy', $purchase));
    $response->assertStatus(404);
});
