<?php

use App\Models\RawMaterial;
use App\Models\RawMaterialPrice;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;

uses(RefreshDatabase::class);

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

function makeValidRawMaterialPayload(array $overrides = []): array
{
    return array_merge([
        'name' => 'Bahan Baku Test',
        'unit' => 'kg',
        'is_active' => true,
        'variants' => [
            [
                'variant' => 'Varian Default',
                'price' => 50000,
                'stock' => 100,
                'photo_key' => 'raw-material-variant/test-photo.jpg',
            ],
        ],
    ], $overrides);
}

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

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

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

test('guests are redirected when visiting edit page', function () {
    $rawMaterial = RawMaterial::factory()->create();
    $response = $this->get(route('admin.master.raw-materials.edit', $rawMaterial));
    $response->assertRedirect(route('login'));
});

test('guest cannot create raw material', function () {
    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload());
    $response->assertRedirect(route('login'));
    $this->assertDatabaseCount('raw_materials', 0);
});

test('guest cannot update raw material', function () {
    $rawMaterial = RawMaterial::factory()->create();
    $response = $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload());
    $response->assertRedirect(route('login'));
});

test('guest cannot delete raw material', function () {
    $rawMaterial = RawMaterial::factory()->create();
    $response = $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));
    $response->assertRedirect(route('login'));
    $this->assertDatabaseHas('raw_materials', ['id' => $rawMaterial->id, 'deleted_at' => null]);
});

test('guest cannot toggle raw material status', function () {
    $rawMaterial = RawMaterial::factory()->create();
    $response = $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));
    $response->assertRedirect(route('login'));
});

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

    $response = $this->get(route('admin.master.raw-materials.index'));
    $response->assertOk();
});

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

    $response = $this->get(route('admin.master.raw-materials.create'));
    $response->assertOk();
});

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

    $rawMaterial = RawMaterial::factory()->create();

    $response = $this->get(route('admin.master.raw-materials.edit', $rawMaterial));
    $response->assertOk();
});

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

test('raw material index page displays raw materials', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

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

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

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

    $response = $this->get(route('admin.master.raw-materials.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/raw-material/index')
        ->has('rawMaterials.data', 0)
        ->where('rawMaterials.total', 0)
        ->where('rawMaterials.current_page', 1)
        ->where('rawMaterials.per_page', 25)
    );
});

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

    RawMaterial::factory()->create(['name' => 'Active Material']);
    RawMaterial::factory()->create(['name' => 'Deleted Material'])->delete();

    $response = $this->get(route('admin.master.raw-materials.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/raw-material/index')
        ->has('rawMaterials.data', 1)
        ->where('rawMaterials.total', 1)
        ->where('rawMaterials.data.0.name', 'Active Material')
    );
});

test('index page displays correct count after delete', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    RawMaterial::factory()->count(5)->create();
    $rawMaterial = RawMaterial::first();

    $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));

    $response = $this->get(route('admin.master.raw-materials.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/raw-material/index')
        ->has('rawMaterials.data', 4)
        ->where('rawMaterials.total', 4)
    );
});

test('index page includes raw material prices (variants)', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->get(route('admin.master.raw-materials.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/raw-material/index')
        ->has('rawMaterials.data.0.raw_material_prices', 1)
    );
});

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

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

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload());
    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.master.raw-materials.index'));

    $this->assertDatabaseHas('raw_materials', [
        'name' => 'Bahan Baku Test',
        'unit' => 'kg',
        'is_active' => true,
    ]);

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

test('raw material can be created with multiple variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [
            ['variant' => 'Varian 1', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/v1.jpg'],
            ['variant' => 'Varian 2', 'price' => 75000, 'stock' => 20, 'photo_key' => 'raw-material-variant/v2.jpg'],
        ],
    ]));

    $response->assertSessionHasNoErrors();

    $this->assertDatabaseCount('raw_material_prices', 2);
});

test('raw material can be created with different units', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    foreach (['kg', 'meter', 'yard'] as $unit) {
        $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
            'name' => "Bahan {$unit}",
            'unit' => $unit,
        ]));
    }

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

test('raw material can be created with zero price', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => 'Gratis', 'price' => 0, 'stock' => 10, 'photo_key' => 'raw-material-variant/free.jpg']],
    ]));

    $response->assertSessionHasNoErrors();

    $price = RawMaterialPrice::where('variant', 'Gratis')->first();
    expect($price->price)->toBe(0);
});

test('raw material can be created with zero stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => 'Kosong', 'price' => 50000, 'stock' => 0, 'photo_key' => 'raw-material-variant/empty.jpg']],
    ]));

    $response->assertSessionHasNoErrors();
});

test('raw material can be created with integer stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => 'Bilangan Bulat', 'price' => 50000, 'stock' => 2, 'photo_key' => 'raw-material-variant/integer.jpg']],
    ]));

    $response->assertSessionHasNoErrors();

    $price = RawMaterialPrice::where('variant', 'Bilangan Bulat')->first();
    expect($price->stock)->toBe(2);
});

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

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['is_active' => false]));
    $response->assertSessionHasNoErrors();

    $rawMaterial = RawMaterial::where('name', 'Bahan Baku Test')->first();
    expect($rawMaterial->is_active)->toBeFalse();
});

test('raw material default is_active is true', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidRawMaterialPayload();
    unset($payload['is_active']);

    $response = $this->post(route('admin.master.raw-materials.store'), $payload);
    $response->assertSessionHasNoErrors();

    $rawMaterial = RawMaterial::where('name', 'Bahan Baku Test')->first();
    expect($rawMaterial->is_active)->toBeTrue();
});

test('store flashes success toast via Inertia', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload());
    $response->assertRedirect();
});

test('store creates new raw material in database', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload());

    $this->assertDatabaseCount('raw_materials', 1);
    $this->assertDatabaseHas('raw_materials', ['name' => 'Bahan Baku Test']);
});

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

    $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => 'Bahan 1']));
    $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => 'Bahan 2']));
    $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => 'Bahan 3']));

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

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

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

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => '']));
    $response->assertSessionHasErrors('name');
});

test('raw material name must be string', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => 12345]));
    $response->assertSessionHasErrors('name');
});

test('raw material name must not exceed 200 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => str_repeat('a', 201)]));
    $response->assertSessionHasErrors('name');
});

test('raw material name exactly 200 characters passes validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['name' => str_repeat('a', 200)]));
    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['unit' => '']));
    $response->assertSessionHasErrors('unit');
});

test('raw material unit must be valid enum value', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['unit' => 'invalid_unit']));
    $response->assertSessionHasErrors('unit');
});

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

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload(['variants' => []]));
    $response->assertSessionHasErrors('variants');
});

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

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

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

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

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

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

test('raw material variant price must be integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidRawMaterialPayload();
    $payload['variants'][0]['price'] = 'not-a-number';

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

test('raw material variant price must be >= 0', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidRawMaterialPayload();
    $payload['variants'][0]['price'] = -100;

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

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

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

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

test('raw material variant stock must be numeric', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidRawMaterialPayload();
    $payload['variants'][0]['stock'] = 'abc';

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

test('raw material variant stock must be >= 0', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidRawMaterialPayload();
    $payload['variants'][0]['stock'] = -1;

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

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

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

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

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

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

    $rawMaterial = RawMaterial::factory()->create(['name' => 'Bahan Edit']);
    RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Varian Edit', 'price' => 50000]);

    $response = $this->get(route('admin.master.raw-materials.edit', $rawMaterial));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/raw-material/edit')
        ->where('rawMaterial.name', 'Bahan Edit')
        ->has('rawMaterial.raw_material_prices', 1)
    );
});

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

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

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Existing']);

    $response = $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'name' => 'Bahan Updated',
        'variants' => [[
            'id' => $variant->id,
            'variant' => 'Existing Updated',
            'price' => 75000,
            'stock' => 50,
            'photo_key' => 'raw-material-variant/existing.jpg',
        ]],
    ]));

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

    $rawMaterial->refresh();
    expect($rawMaterial->name)->toBe('Bahan Updated');
});

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

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload(['name' => '']));
    $response->assertSessionHasErrors('name');
});

test('raw material update name must not exceed 200 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload(['name' => str_repeat('a', 201)]));
    $response->assertSessionHasErrors('name');
});

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

    $response = $this->put(route('admin.master.raw-materials.update', 999999), makeValidRawMaterialPayload(['name' => 'Ghost']));
    $response->assertStatus(404);
});

test('update can change raw material status', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['is_active' => true]);
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'is_active' => false,
        'variants' => [[
            'id' => $variant->id,
            'variant' => $variant->variant,
            'price' => $variant->price,
            'stock' => $variant->stock,
            'photo_key' => 'raw-material-variant/v1.jpg',
        ]],
    ]));

    $rawMaterial->refresh();
    expect($rawMaterial->is_active)->toBeFalse();
});

test('update can change unit', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['unit' => 'kg']);
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'unit' => 'meter',
        'variants' => [[
            'id' => $variant->id,
            'variant' => $variant->variant,
            'price' => $variant->price,
            'stock' => $variant->stock,
            'photo_key' => 'raw-material-variant/v1.jpg',
        ]],
    ]));

    $rawMaterial->refresh();
    expect($rawMaterial->unit->value)->toBe('meter');
});

test('update can add new variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $existingVariant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Existing']);

    $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'variants' => [
            ['id' => $existingVariant->id, 'variant' => 'Existing', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/existing.jpg'],
            ['variant' => 'New Variant', 'price' => 75000, 'stock' => 20, 'photo_key' => 'raw-material-variant/new.jpg'],
        ],
    ]));

    $this->assertDatabaseCount('raw_material_prices', 2);
});

test('update can delete variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant1 = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Keep']);
    $variant2 = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Delete']);

    $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'variants' => [
            ['id' => $variant1->id, 'variant' => 'Keep', 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/keep.jpg'],
        ],
    ]));

    $this->assertDatabaseHas('raw_material_prices', ['id' => $variant1->id, 'deleted_at' => null]);
    $this->assertSoftDeleted('raw_material_prices', ['id' => $variant2->id]);
});

test('update can modify existing variant data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create([
        'raw_material_id' => $rawMaterial->id,
        'variant' => 'Original',
        'price' => 50000,
        'stock' => 10,
    ]);

    $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload([
        'variants' => [[
            'id' => $variant->id,
            'variant' => 'Updated Name',
            'price' => 99999,
            'stock' => 88,
            'photo_key' => 'raw-material-variant/updated.jpg',
        ]],
    ]));

    $variant->refresh();
    expect($variant->variant)->toBe('Updated Name');
    expect($variant->price)->toBe(99999);
    expect((float) $variant->stock)->toBe(88.0);
});

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

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

    $rawMaterial = RawMaterial::factory()->create();

    $response = $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.master.raw-materials.index'));

    $this->assertSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
});

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

    $rawMaterial = RawMaterial::factory()->create();

    $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));

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

test('soft-deleted raw material has deleted_at timestamp', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();

    $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));

    $rawMaterial->refresh();
    expect($rawMaterial->deleted_at)->not->toBeNull();
});

test('delete cascades to raw material prices', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));

    $this->assertSoftDeleted('raw_material_prices', ['id' => $variant->id]);
});

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

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

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

    $rawMaterial = RawMaterial::factory()->create();
    $rawMaterial->delete();

    $response = $this->put(route('admin.master.raw-materials.update', $rawMaterial), makeValidRawMaterialPayload(['name' => 'Nope']));
    $response->assertStatus(404);
});

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

    $rawMaterial = RawMaterial::factory()->create();
    $rawMaterial->delete();

    $response = $this->delete(route('admin.master.raw-materials.destroy', $rawMaterial));
    $response->assertStatus(404);
});

/*
|--------------------------------------------------------------------------
| TOGGLE STATUS
|--------------------------------------------------------------------------
*/

test('toggle status changes active to inactive', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['is_active' => true]);

    $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));

    $rawMaterial->refresh();
    expect($rawMaterial->is_active)->toBeFalse();
});

test('toggle status changes inactive to active', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['is_active' => false]);

    $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));

    $rawMaterial->refresh();
    expect($rawMaterial->is_active)->toBeTrue();
});

test('toggle status changes active to inactive then back to active', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['is_active' => true]);

    $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));
    $rawMaterial->refresh();
    expect($rawMaterial->is_active)->toBeFalse();

    $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));
    $rawMaterial->refresh();
    expect($rawMaterial->is_active)->toBeTrue();
});

test('toggle status redirects to index', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create(['is_active' => true]);

    $response = $this->post(route('admin.master.raw-materials.toggle-status', $rawMaterial));
    $response->assertRedirect(route('admin.master.raw-materials.index'));
});

test('toggle status on non-existent raw material returns 404', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.toggle-status', 999999));
    $response->assertStatus(404);
});

/*
|--------------------------------------------------------------------------
| WEIRD / EDGE CASE USER INPUTS
|--------------------------------------------------------------------------
*/

test('raw material name with special characters is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'name' => 'Bahan & Co. (PT) - Best!',
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('raw_materials', ['name' => 'Bahan & Co. (PT) - Best!']);
});

test('raw material name with HTML tags is accepted as plain text', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'name' => '<script>alert("xss")</script>',
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('raw_materials', ['name' => '<script>alert("xss")</script>']);
});

test('raw material name with emoji is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'name' => '🧵 Bahan Kain 🏷️',
    ]));

    $response->assertSessionHasNoErrors();
});

test('raw material name with only numbers is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'name' => '12345',
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('raw_materials', ['name' => '12345']);
});

test('raw material name with SQL injection attempt is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'name' => "'; DROP TABLE raw_materials; --",
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('raw_materials', ['name' => "'; DROP TABLE raw_materials; --"]);
});

test('raw material variant name at max length 200 is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => str_repeat('a', 200), 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/maxlen.jpg']],
    ]));

    $response->assertSessionHasNoErrors();
});

test('raw material variant name over 200 characters fails validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => str_repeat('a', 201), 'price' => 50000, 'stock' => 10, 'photo_key' => 'raw-material-variant/overmax.jpg']],
    ]));

    $response->assertSessionHasErrors('variants.0.variant');
});

test('raw material stock at very large value is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => 'Varian Besar', 'price' => 50000, 'stock' => 99999999, 'photo_key' => 'raw-material-variant/huge.jpg']],
    ]));

    $response->assertSessionHasNoErrors();
});

test('raw material price at very large value is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.raw-materials.store'), makeValidRawMaterialPayload([
        'variants' => [['variant' => 'Varian Mahal', 'price' => 999999999, 'stock' => 1, 'photo_key' => 'raw-material-variant/expensive.jpg']],
    ]));

    $response->assertSessionHasNoErrors();
});

/*
|--------------------------------------------------------------------------
| VARIANT EDIT / UPDATE
|--------------------------------------------------------------------------
*/

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

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id, 'variant' => 'Old Name', 'price' => 50000, 'stock' => 10]);

    $response = $this->put(route('admin.master.raw-materials.variants.update', [$rawMaterial, $variant]), [
        'variant' => 'New Name',
        'price' => 75000,
        'stock' => 20,
        'photo_key' => 'raw-material-variant/updated.jpg',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.master.raw-materials.index'));

    $variant->refresh();
    expect($variant->variant)->toBe('New Name');
    expect($variant->price)->toBe(75000);
    expect((float) $variant->stock)->toBe(20.0);
});

test('variant update validation requires variant name', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.variants.update', [$rawMaterial, $variant]), [
        'variant' => '',
        'price' => 50000,
        'stock' => 10,
        'photo_key' => 'raw-material-variant/v1.jpg',
    ]);

    $response->assertSessionHasErrors('variant');
});

test('variant update validation requires price', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.variants.update', [$rawMaterial, $variant]), [
        'variant' => 'Test',
        'stock' => 10,
        'photo_key' => 'raw-material-variant/v1.jpg',
    ]);

    $response->assertSessionHasErrors('price');
});

test('variant update validation requires stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.variants.update', [$rawMaterial, $variant]), [
        'variant' => 'Test',
        'price' => 50000,
        'photo_key' => 'raw-material-variant/v1.jpg',
    ]);

    $response->assertSessionHasErrors('stock');
});

test('variant update validation requires photo_key', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->put(route('admin.master.raw-materials.variants.update', [$rawMaterial, $variant]), [
        'variant' => 'Test',
        'price' => 50000,
        'stock' => 10,
    ]);

    $response->assertSessionHasErrors('photo_key');
});

/*
|--------------------------------------------------------------------------
| VARIANT DELETE
|--------------------------------------------------------------------------
*/

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

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $response = $this->delete(route('admin.master.raw-materials.variants.destroy', [$rawMaterial, $variant]));

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.master.raw-materials.index'));

    $this->assertSoftDeleted('raw_material_prices', ['id' => $variant->id]);
});

test('deleting variant does not affect raw material', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $rawMaterial = RawMaterial::factory()->create();
    $variant = RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);

    $this->delete(route('admin.master.raw-materials.variants.destroy', [$rawMaterial, $variant]));

    $this->assertDatabaseHas('raw_materials', ['id' => $rawMaterial->id, 'deleted_at' => null]);
});
