<?php

use App\Models\Category;
use App\Models\Product;
use App\Models\ProductPrice;
use App\Models\ProductVariant;
use App\Models\StockMutation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia as Assert;

uses(RefreshDatabase::class);

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

function makeValidProductPayload(array $overrides = []): array
{
    $category = Category::factory()->create();

    return array_merge([
        'name' => 'Produk Test',
        'description' => 'Deskripsi produk',
        'status' => 'active',
        'category_ids' => [$category->id],
        'use_same_price' => false,
        'shared_prices' => [],
        'variants' => [
            [
                'name' => 'Varian Default',
                'stock' => 100,
                'reject_stock' => 10,
                'retail_stock' => 20,
                'photo_keys' => ['product-variant/test-photo.jpg'],
                'prices' => [
                    ['type' => 'distributor', 'price' => 10000],
                    ['type' => 'agent', 'price' => 11000],
                    ['type' => 'sub_agent', 'price' => 12000],
                    ['type' => 'wholesale', 'price' => 13000],
                    ['type' => 'retail', 'price' => 15000],
                    ['type' => 'tiktok', 'price' => 16000],
                    ['type' => 'shopee', 'price' => 16500],
                    ['type' => 'capital', 'price' => 8000],
                    ['type' => 'reject', 'price' => 5000],
                ],
            ],
        ],
    ], $overrides);
}

function makeValidSharedPricePayload(array $overrides = []): array
{
    $category = Category::factory()->create();

    return array_merge([
        'name' => 'Produk Shared Price',
        'description' => null,
        'status' => 'active',
        'category_ids' => [$category->id],
        'use_same_price' => true,
        'shared_prices' => [
            ['type' => 'distributor', 'price' => 10000],
            ['type' => 'agent', 'price' => 11000],
            ['type' => 'sub_agent', 'price' => 12000],
            ['type' => 'wholesale', 'price' => 13000],
            ['type' => 'retail', 'price' => 15000],
            ['type' => 'tiktok', 'price' => 16000],
            ['type' => 'shopee', 'price' => 16500],
            ['type' => 'capital', 'price' => 8000],
            ['type' => 'reject', 'price' => 5000],
        ],
        'variants' => [
            [
                'name' => 'Varian Shared',
                'stock' => 50,
                'reject_stock' => 5,
                'retail_stock' => 10,
                'photo_keys' => ['product-variant/shared-photo.jpg'],
                'prices' => [],
            ],
        ],
    ], $overrides);
}

function allPriceTypes(): array
{
    return [
        ['type' => 'distributor', 'price' => 10000],
        ['type' => 'agent', 'price' => 11000],
        ['type' => 'sub_agent', 'price' => 12000],
        ['type' => 'wholesale', 'price' => 13000],
        ['type' => 'retail', 'price' => 15000],
        ['type' => 'tiktok', 'price' => 16000],
        ['type' => 'shopee', 'price' => 16500],
        ['type' => 'capital', 'price' => 8000],
        ['type' => 'reject', 'price' => 5000],
    ];
}

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

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

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

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

test('guest cannot create product', function () {
    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload());
    $response->assertRedirect(route('login'));
    $this->assertDatabaseCount('products', 0);
});

test('guest cannot update product', function () {
    $product = Product::factory()->create();
    $response = $this->put(route('admin.master.products.update', $product), makeValidProductPayload());
    $response->assertRedirect(route('login'));
});

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

test('guest cannot toggle product status', function () {
    $product = Product::factory()->create();
    $response = $this->post(route('admin.master.products.toggle-status', $product));
    $response->assertRedirect(route('login'));
});

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

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

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

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

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

    $product = Product::factory()->create();

    $response = $this->get(route('admin.master.products.edit', $product));
    $response->assertOk();
});

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

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

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

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

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

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

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

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

    $response = $this->get(route('admin.master.products.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/index')
        ->has('products.data', 1)
        ->where('products.total', 1)
        ->where('products.current_page', 1)
        ->where('products.per_page', 25)
        ->where('products.data.0.name', 'Active Product')
    );
});

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

    Product::factory()->count(5)->create();
    $product = Product::first();

    $this->delete(route('admin.master.products.destroy', $product));

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

test('index page includes product categories', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);

    $response = $this->get(route('admin.master.products.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/index')
        ->has('products.data.0.categories', 1)
    );
});

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

    $product = Product::factory()->create();
    ProductVariant::factory()->create(['product_id' => $product->id]);

    $response = $this->get(route('admin.master.products.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/index')
        ->has('products.data.0.product_variants', 1)
    );
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);
    ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => 'retail', 'price' => 15000]);

    $response = $this->get(route('admin.master.products.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/index')
        ->has('products.data.0.product_variants.0.product_prices', 1)
    );
});

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

test('product can be created with per-variant prices', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

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

    $this->assertDatabaseHas('products', [
        'name' => 'Produk Test',
        'status' => 'active',
    ]);

    $this->assertDatabaseCount('product_variants', 1);
    $this->assertDatabaseCount('product_prices', 9);
});

test('product can be created with shared prices', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

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

    $this->assertDatabaseHas('products', ['name' => 'Produk Shared Price']);
    $this->assertDatabaseCount('product_variants', 1);
    $this->assertDatabaseCount('product_prices', 9);
});

test('product slug is automatically generated from name', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk Otomatis']));

    $this->assertDatabaseHas('products', [
        'name' => 'Produk Otomatis',
        'slug' => 'produk-otomatis',
    ]);
});

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

    $categories = Category::factory()->count(3)->create();

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'category_ids' => $categories->pluck('id')->toArray(),
    ]));

    $response->assertSessionHasNoErrors();

    $product = Product::where('name', 'Produk Test')->first();
    $this->assertCount(3, $product->categories);
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [
            [
                'name' => 'Varian 1',
                'stock' => 10,
                'reject_stock' => 1,
                'retail_stock' => 2,
                'photo_keys' => ['product-variant/v1.jpg'],
                'prices' => allPriceTypes(),
            ],
            [
                'name' => 'Varian 2',
                'stock' => 20,
                'reject_stock' => 2,
                'retail_stock' => 4,
                'photo_keys' => ['product-variant/v2.jpg'],
                'prices' => array_map(fn ($p) => ['type' => $p['type'], 'price' => $p['price'] * 2], allPriceTypes()),
            ],
        ],
    ]));

    $response->assertSessionHasNoErrors();

    $this->assertDatabaseCount('product_variants', 2);
    $this->assertDatabaseCount('product_prices', 18);
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Gratis',
            'stock' => 10,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/free.jpg'],
            'prices' => array_map(fn ($p) => ['type' => $p['type'], 'price' => 0], allPriceTypes()),
        ]],
    ]));

    $response->assertSessionHasNoErrors();

    $variant = ProductVariant::where('name', 'Varian Gratis')->first();
    $prices = ProductPrice::where('variant_id', $variant->id)->get();
    expect($prices->pluck('price')->toArray())->toEqual([0, 0, 0, 0, 0, 0, 0, 0, 0]);
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Mahal',
            'stock' => 1,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/expensive.jpg'],
            'prices' => array_map(fn ($p) => ['type' => $p['type'], 'price' => 999999999], allPriceTypes()),
        ]],
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Kosong',
            'stock' => 0,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/empty.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $response->assertSessionHasNoErrors();
});

test('product can be created with default status when not provided', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidProductPayload();
    unset($payload['status']);

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

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->status->value)->toBe('active');
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'draft']));
    $response->assertSessionHasNoErrors();

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->status->value)->toBe('draft');
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'inactive']));
    $response->assertSessionHasNoErrors();

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->status->value)->toBe('inactive');
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['description' => null]));
    $response->assertSessionHasNoErrors();

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->description)->toBeNull();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload());
    $response->assertRedirect();
});

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

    $this->post(route('admin.master.products.store'), makeValidProductPayload());

    $this->assertDatabaseCount('products', 1);
    $this->assertDatabaseHas('products', [
        'name' => 'Produk Test',
        'slug' => 'produk-test',
    ]);
});

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

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk 1']));
    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk 2']));
    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk 3']));

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

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

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

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

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

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

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

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

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

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

test('product name exactly 1 character passes validation', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'A']));
    $response->assertSessionHasNoErrors();
});

test('product name with only whitespace is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

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

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['category_ids' => []]));
    $response->assertSessionHasErrors('category_ids');
});

test('product category_ids must be array', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['category_ids' => 'not-an-array']));
    $response->assertSessionHasErrors('category_ids');
});

test('product category_ids.* must exist in categories table', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['category_ids' => [999999]]));
    $response->assertSessionHasErrors('category_ids.0');
});

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

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

test('product variants must be array', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['variants' => 'not-an-array']));
    $response->assertSessionHasErrors('variants');
});

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

    $payload = makeValidProductPayload();
    $payload['variants'][0]['name'] = '';

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

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

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

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

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

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

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

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

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

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

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

    $payload = makeValidProductPayload();
    $payload['variants'][0]['reject_stock'] = -5;

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

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

    $payload = makeValidProductPayload();
    $payload['variants'][0]['retail_stock'] = -3;

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

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

    $payload = makeValidProductPayload();
    unset($payload['variants'][0]['photo_keys']);

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

/*
|--------------------------------------------------------------------------
| STORE VALIDATION - STATUS
|--------------------------------------------------------------------------
*/

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'invalid_status']));
    $response->assertSessionHasErrors('status');
});

test('product status accepts active', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'active']));
    $response->assertSessionHasNoErrors();
});

test('product status accepts inactive', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'inactive']));
    $response->assertSessionHasNoErrors();
});

test('product status accepts draft', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['status' => 'draft']));
    $response->assertSessionHasNoErrors();
});

/*
|--------------------------------------------------------------------------
| STORE VALIDATION - PRICES
|--------------------------------------------------------------------------
*/

test('product prices are required when use_same_price is false', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidProductPayload();
    $payload['variants'][0]['prices'] = [];

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

test('product prices must have exactly 9 items when use_same_price is false', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidProductPayload();
    $payload['variants'][0]['prices'] = [
        ['type' => 'retail', 'price' => 10000],
        ['type' => 'wholesale', 'price' => 12000],
    ];

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

test('product price type must be valid PriceType enum', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidProductPayload();
    $payload['variants'][0]['prices'][0]['type'] = 'invalid_type';

    $response = $this->post(route('admin.master.products.store'), $payload);
    $response->assertSessionHasErrors('variants.0.prices.0.type');
});

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

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

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

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

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

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

test('shared_prices are required when use_same_price is true', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidSharedPricePayload();
    $payload['shared_prices'] = [];

    $response = $this->post(route('admin.master.products.store'), $payload);
    $response->assertSessionHasErrors('shared_prices');
});

test('shared_prices must have exactly 9 items when use_same_price is true', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidSharedPricePayload();
    $payload['shared_prices'] = [
        ['type' => 'retail', 'price' => 10000],
    ];

    $response = $this->post(route('admin.master.products.store'), $payload);
    $response->assertSessionHasErrors('shared_prices');
});

test('shared_price type must be valid PriceType enum', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidSharedPricePayload();
    $payload['shared_prices'][0]['type'] = 'invalid_type';

    $response = $this->post(route('admin.master.products.store'), $payload);
    $response->assertSessionHasErrors('shared_prices.0.type');
});

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

    $payload = makeValidSharedPricePayload();
    $payload['shared_prices'][0]['price'] = -500;

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

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

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

    $product = Product::factory()->create(['name' => 'Produk Edit']);
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);
    ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => 'retail', 'price' => 15000]);

    $response = $this->get(route('admin.master.products.edit', $product));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/edit')
        ->where('product.name', 'Produk Edit')
        ->has('product.product_variants', 1)
    );
});

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

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

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id, 'name' => 'Existing']);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $response = $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => 'Produk Updated',
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => 'Existing Updated',
            'stock' => 100,
            'reject_stock' => 10,
            'retail_stock' => 20,
            'photo_keys' => ['product-variant/existing.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

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

    $product->refresh();
    expect($product->name)->toBe('Produk Updated');
});

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

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $response = $this->put(route('admin.master.products.update', $product), makeValidProductPayload(['name' => '']));
    $response->assertSessionHasErrors('name');
});

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

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $response = $this->put(route('admin.master.products.update', $product), makeValidProductPayload(['name' => str_repeat('a', 201)]));
    $response->assertSessionHasErrors('name');
});

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

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

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

    $product = Product::factory()->create(['status' => 'active']);
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id, 'name' => 'V1']);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'status' => 'draft',
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => 'V1',
            'stock' => 100,
            'reject_stock' => 10,
            'retail_stock' => 20,
            'photo_keys' => ['product-variant/v1.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $product->refresh();
    expect($product->status->value)->toBe('draft');
});

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

    $product = Product::factory()->create();
    $oldCategory = Category::factory()->create();
    $newCategory = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $oldCategory->id,
    ]);
    $variant = ProductVariant::factory()->create(['product_id' => $product->id, 'name' => 'V1']);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'category_ids' => [$newCategory->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => 'V1',
            'stock' => 100,
            'reject_stock' => 10,
            'retail_stock' => 20,
            'photo_keys' => ['product-variant/v1.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $product->refresh();
    $this->assertCount(1, $product->categories);
    expect($product->categories->first()->id)->toBe($newCategory->id);
});

test('update replaces old variants with new ones', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'To Replace']));
    $product = Product::where('name', 'To Replace')->first();
    $category = $product->categories->first();
    $oldVariant = $product->productVariants->first();
    $oldVariantId = $oldVariant->id;

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => 'Replaced',
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $oldVariantId,
            'name' => 'New Variant',
            'stock' => 42,
            'reject_stock' => 3,
            'retail_stock' => 7,
            'photo_keys' => ['product-variant/new.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $product->refresh();
    $variant = ProductVariant::where('id', $oldVariantId)->first();
    expect($variant->name)->toBe('New Variant');
    expect($variant->stock)->toBe(42);
});

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

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Modify Variant']));
    $product = Product::where('name', 'Modify Variant')->first();
    $category = $product->categories->first();
    $existingVariant = $product->productVariants->first();

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => 'Modify Variant',
        'category_ids' => [$category->id],
        'variants' => [
            [
                'id' => $existingVariant->id,
                'name' => 'Updated Variant Name',
                'stock' => 999,
                'reject_stock' => 50,
                'retail_stock' => 75,
                'photo_keys' => ['product-variant/updated.jpg'],
                'prices' => allPriceTypes(),
            ],
        ],
    ]));

    $product->refresh();
    $variant = $product->productVariants->first();
    expect($variant->name)->toBe('Updated Variant Name');
    expect($variant->stock)->toBe(999);
    expect($variant->reject_stock)->toBe(50);
    expect($variant->retail_stock)->toBe(75);
});

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

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

    $product = Product::factory()->create();

    $response = $this->delete(route('admin.master.products.destroy', $product));

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

    $this->assertSoftDeleted('products', ['id' => $product->id]);
});

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

    $product = Product::factory()->create();

    $this->delete(route('admin.master.products.destroy', $product));

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

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

    $product = Product::factory()->create();

    $this->delete(route('admin.master.products.destroy', $product));

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

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);

    $this->delete(route('admin.master.products.destroy', $product));

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

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);
    ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => 'retail', 'price' => 15000]);

    $this->delete(route('admin.master.products.destroy', $product));

    $this->assertDatabaseCount('product_prices', 0);
});

test('delete detaches product categories', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);

    $this->delete(route('admin.master.products.destroy', $product));

    $this->assertDatabaseCount('product_categories', 0);
});

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

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

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

    $product = Product::factory()->create();
    $product->delete();

    $response = $this->put(route('admin.master.products.update', $product), makeValidProductPayload(['name' => 'Nope']));
    $response->assertStatus(404);
});

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

    $product = Product::factory()->create();
    $product->delete();

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

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

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

    $product = Product::factory()->create(['status' => 'active']);

    $this->post(route('admin.master.products.toggle-status', $product));

    $product->refresh();
    expect($product->status->value)->toBe('inactive');
});

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

    $product = Product::factory()->create(['status' => 'inactive']);

    $this->post(route('admin.master.products.toggle-status', $product));

    $product->refresh();
    expect($product->status->value)->toBe('active');
});

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

    $product = Product::factory()->create(['status' => 'draft']);

    $this->post(route('admin.master.products.toggle-status', $product));

    $product->refresh();
    expect($product->status->value)->toBe('active');
});

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

    $product = Product::factory()->create(['status' => 'active']);

    $this->post(route('admin.master.products.toggle-status', $product));
    $product->refresh();
    expect($product->status->value)->toBe('inactive');

    $this->post(route('admin.master.products.toggle-status', $product));
    $product->refresh();
    expect($product->status->value)->toBe('active');
});

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

    $product = Product::factory()->create(['status' => 'active']);

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

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

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

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

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'Produk & Co. (PT) - Best!',
    ]));

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

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

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

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

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '🔥 Hot Product 🏷️',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => ' Produk Žöžička ',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '电子产品',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '製品テスト',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'المنتج',
    ]));

    $response->assertSessionHasNoErrors();
});

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

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

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

test('product name with email-like pattern is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'product@example.com',
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with URL-like pattern is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'https://example.com/product',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => "'; DROP TABLE products; --",
    ]));

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

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => '<b>Size</b> XL (🔥)',
            'stock' => 10,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/weird.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => str_repeat('a', 200),
            'stock' => 10,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/maxlen.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => str_repeat('a', 201),
            'stock' => 10,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/overmax.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

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

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Besar',
            'stock' => 2147483647,
            'reject_stock' => 2147483647,
            'retail_stock' => 2147483647,
            'photo_keys' => ['product-variant/huge.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $response->assertSessionHasNoErrors();
});

test('product variant name with only whitespace is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => '   ',
            'stock' => 10,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/whitespace.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

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

test('product with description containing newlines is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'description' => "Baris 1\nBaris 2\nBaris 3",
    ]));

    $response->assertSessionHasNoErrors();
});

test('product with very long description is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'description' => str_repeat('Deskripsi produk panjang. ', 100),
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'A & B (v2.0) - Best Product!',
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('products', ['slug' => 'a-b-v20-best-product']);
});

test('product name with leading and trailing spaces is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '  Produk Spasi  ',
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with multiple spaces generates correct slug', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'Produk   dengan   spasi   banyak',
    ]));

    $this->assertDatabaseHas('products', [
        'name' => 'Produk   dengan   spasi   banyak',
        'slug' => 'produk-dengan-spasi-banyak',
    ]);
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => "Produk\nBaru",
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with curly braces is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '{code} Product',
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with angle brackets is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '<Product> Name',
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with pipe symbol is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'A|B Product',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'Product;Injected',
    ]));

    $response->assertSessionHasNoErrors();
});

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

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '`Code` Product',
    ]));

    $response->assertSessionHasNoErrors();
});

test('product name with date-like pattern is accepted', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => 'Product 2024-01-15',
    ]));

    $response->assertSessionHasNoErrors();
});

test('shared_price with string price containing dots is rejected as not integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidSharedPricePayload([
        'shared_prices' => array_map(fn ($p) => ['type' => $p['type'], 'price' => '15.000'], allPriceTypes()),
    ]));

    $response->assertSessionHasErrors('shared_prices.0.price');
});

test('shared_price with string price with thousands separator is rejected as not integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidSharedPricePayload([
        'shared_prices' => array_map(fn ($p) => ['type' => $p['type'], 'price' => '1.250.000'], allPriceTypes()),
    ]));

    $response->assertSessionHasErrors('shared_prices.0.price');
});

/*
|--------------------------------------------------------------------------
| DATA INTEGRITY
|--------------------------------------------------------------------------
*/

test('created product has correct timestamps', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload());

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->created_at)->not->toBeNull();
    expect($product->updated_at)->not->toBeNull();
});

test('product factory creates valid product', function () {
    $product = Product::factory()->create();

    expect($product->name)->not->toBeEmpty();
    expect($product->slug)->not->toBeEmpty();
    expect($product->id)->toBeInt();
});

test('product price is stored as integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload());

    $price = ProductPrice::first();
    expect($price->price)->toBeInt();
});

test('product variant has correct relationships', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->create(['product_id' => $product->id]);

    expect($variant->product->id)->toBe($product->id);
    expect($variant->productPrices)->toHaveCount(0);
});

test('product price belongs to variant', function () {
    $variant = ProductVariant::factory()->create();
    $price = ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => 'retail', 'price' => 15000]);

    expect($price->variant->id)->toBe($variant->id);
    expect($price->type->value)->toBe('retail');
    expect($price->type_label)->toBe('Ecer');
});

test('product categories are synced correctly on create', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $cat1 = Category::factory()->create();
    $cat2 = Category::factory()->create();

    $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'category_ids' => [$cat1->id, $cat2->id],
    ]));

    $product = Product::where('name', 'Produk Test')->first();
    $this->assertCount(2, $product->categories);
});

/*
|--------------------------------------------------------------------------
| REALISTIC USER SCENARIOS
|--------------------------------------------------------------------------
*/

test('user creates product then immediately edits it', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Draft Product']));
    $product = Product::where('name', 'Draft Product')->first();

    $category = $product->categories->first();
    $variant = $product->productVariants->first();

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => 'Final Product',
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => $variant->name,
            'stock' => $variant->stock,
            'reject_stock' => $variant->reject_stock,
            'retail_stock' => $variant->retail_stock,
            'photo_keys' => ['product-variant/final.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $product->refresh();
    expect($product->name)->toBe('Final Product');
});

test('user creates multiple products and deletes one', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Keep']));
    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Delete Me']));
    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Also Keep']));

    $toDelete = Product::where('name', 'Delete Me')->first();
    $this->delete(route('admin.master.products.destroy', $toDelete));

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

test('user toggles product status multiple times', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create(['status' => 'active']);

    $this->post(route('admin.master.products.toggle-status', $product));
    $product->refresh();
    expect($product->status->value)->toBe('inactive');

    $this->post(route('admin.master.products.toggle-status', $product));
    $product->refresh();
    expect($product->status->value)->toBe('active');

    $this->post(route('admin.master.products.toggle-status', $product));
    $product->refresh();
    expect($product->status->value)->toBe('inactive');
});

test('user creates product with 10 variants each with 9 prices', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $variants = [];
    for ($i = 0; $i < 10; $i++) {
        $variants[] = [
            'name' => "Varian {$i}",
            'stock' => $i * 10,
            'reject_stock' => $i,
            'retail_stock' => $i * 2,
            'photo_keys' => ["product-variant/v{$i}.jpg"],
            'prices' => allPriceTypes(),
        ];
    }

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => $variants,
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseCount('product_variants', 10);
    $this->assertDatabaseCount('product_prices', 90);
});

test('user creates product then deletes it and creates another with same name', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk']));
    $product = Product::where('name', 'Produk')->first();
    $this->delete(route('admin.master.products.destroy', $product));

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Produk']));
    $response->assertSessionHasNoErrors();

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

test('user submits empty form and gets all required errors', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), []);

    $response->assertSessionHasErrors(['name', 'category_ids', 'variants']);
});

test('user creates product with very long description containing special chars', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $description = str_repeat('Produk & Co. (PT) - Best! <b>Bold</b> ', 50);
    $trimmed = trim($description);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'description' => $description,
    ]));

    $response->assertSessionHasNoErrors();

    $product = Product::where('name', 'Produk Test')->first();
    expect($product->description)->toBe($trimmed);
});

test('index page works with products that have many variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    ProductVariant::factory()->count(20)->create(['product_id' => $product->id]);

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

test('delete product does not affect other products', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product1 = Product::factory()->create(['name' => 'Product 1']);
    $product2 = Product::factory()->create(['name' => 'Product 2']);

    $variant1 = ProductVariant::factory()->create(['product_id' => $product1->id]);
    $variant2 = ProductVariant::factory()->create(['product_id' => $product2->id]);

    ProductPrice::factory()->create(['variant_id' => $variant1->id, 'type' => 'retail', 'price' => 10000]);
    ProductPrice::factory()->create(['variant_id' => $variant2->id, 'type' => 'retail', 'price' => 20000]);

    $this->delete(route('admin.master.products.destroy', $product1));

    $this->assertSoftDeleted('products', ['id' => $product1->id]);
    $this->assertDatabaseHas('products', ['id' => $product2->id, 'deleted_at' => null]);
    $this->assertDatabaseCount('product_prices', 1);
    $this->assertDatabaseHas('product_prices', ['variant_id' => $variant2->id, 'price' => 20000]);
});

test('user can create product with name that is a number string', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'name' => '007',
    ]));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseHas('products', ['name' => '007', 'slug' => '007']);
});

test('user rapidly creates two products with same name', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Rapid Product']));
    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload(['name' => 'Rapid Product']));

    $response->assertSessionHasNoErrors();
    $this->assertDatabaseCount('products', 2);
});

test('product can be created with all price types having different values', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $prices = [
        ['type' => 'distributor', 'price' => 10000],
        ['type' => 'agent', 'price' => 11000],
        ['type' => 'sub_agent', 'price' => 12000],
        ['type' => 'wholesale', 'price' => 13000],
        ['type' => 'retail', 'price' => 15000],
        ['type' => 'tiktok', 'price' => 16000],
        ['type' => 'shopee', 'price' => 16500],
        ['type' => 'capital', 'price' => 8000],
        ['type' => 'reject', 'price' => 5000],
    ];

    $response = $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Semua Harga',
            'stock' => 100,
            'reject_stock' => 10,
            'retail_stock' => 20,
            'photo_keys' => ['product-variant/all-prices.jpg'],
            'prices' => $prices,
        ]],
    ]));

    $response->assertSessionHasNoErrors();

    $variant = ProductVariant::where('name', 'Semua Harga')->first();
    $dbPrices = ProductPrice::where('variant_id', $variant->id)->get();

    expect($dbPrices)->toHaveCount(9);
    expect($dbPrices->firstWhere('type', 'distributor')->price)->toBe(10000);
    expect($dbPrices->firstWhere('type', 'reject')->price)->toBe(5000);
});

test('shared price applies to all variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->post(route('admin.master.products.store'), makeValidSharedPricePayload([
        'variants' => [
            ['name' => 'V1', 'stock' => 10, 'reject_stock' => 0, 'retail_stock' => 0, 'photo_keys' => ['v1.jpg'], 'prices' => []],
            ['name' => 'V2', 'stock' => 20, 'reject_stock' => 0, 'retail_stock' => 0, 'photo_keys' => ['v2.jpg'], 'prices' => []],
        ],
    ]));

    $response->assertSessionHasNoErrors();

    $this->assertDatabaseCount('product_variants', 2);
    $this->assertDatabaseCount('product_prices', 18);

    $v1 = ProductVariant::where('name', 'V1')->first();
    $v2 = ProductVariant::where('name', 'V2')->first();

    $v1Prices = ProductPrice::where('variant_id', $v1->id)->pluck('price')->toArray();
    $v2Prices = ProductPrice::where('variant_id', $v2->id)->pluck('price')->toArray();

    expect($v1Prices)->toEqual($v2Prices);
});

test('user tries to store with invalid use_same_price boolean', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $payload = makeValidProductPayload();
    $payload['use_same_price'] = 'maybe';

    $response = $this->post(route('admin.master.products.store'), $payload);
    // 'maybe' is truthy in PHP so use_same_price becomes true
    // but shared_prices is empty, so it should fail
    $response->assertSessionHasErrors('shared_prices');
});

/*
|--------------------------------------------------------------------------
| PRODUCT VARIANT - EDIT PAGE
|--------------------------------------------------------------------------
*/

test('guest cannot access variant edit page', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->get(route('admin.master.products.variants.edit', [$product, $variant]));
    $response->assertRedirect(route('login'));
});

test('authenticated user can access variant edit page', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->get(route('admin.master.products.variants.edit', [$product, $variant]));
    $response->assertStatus(200);
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/edit')
        ->has('variant')
    );
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create([
        'name' => 'Varian Edit Test',
        'stock' => 100,
        'reject_stock' => 10,
        'retail_stock' => 20,
    ]);

    $response = $this->get(route('admin.master.products.variants.edit', [$product, $variant]));
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/edit')
        ->where('variant.id', $variant->id)
        ->where('variant.product_id', $product->id)
        ->where('variant.name', 'Varian Edit Test')
        ->where('variant.stock', 100)
        ->where('variant.reject_stock', 10)
        ->where('variant.retail_stock', 20)
    );
});

/*
|--------------------------------------------------------------------------
| PRODUCT VARIANT - UPDATE
|--------------------------------------------------------------------------
*/

test('guest cannot update variant', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => 'Updated',
        'stock' => 50,
        'reject_stock' => 5,
        'retail_stock' => 10,
        'photo_keys' => ['product-variant/updated.jpg'],
        'prices' => allPriceTypes(),
    ]);

    $response->assertRedirect(route('login'));
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create([
        'name' => 'Original Name',
        'stock' => 100,
    ]);

    $response = $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => 'Updated Name',
        'stock' => 200,
        'reject_stock' => 15,
        'retail_stock' => 25,
        'photo_keys' => ['product-variant/new-photo.jpg'],
        'prices' => allPriceTypes(),
    ]);

    $response->assertRedirect();
    $this->assertDatabaseHas('product_variants', [
        'id' => $variant->id,
        'name' => 'Updated Name',
        'stock' => 200,
        'reject_stock' => 15,
        'retail_stock' => 25,
    ]);
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    ProductPrice::create([
        'variant_id' => $variant->id,
        'type' => 'retail',
        'price' => 10000,
    ]);

    $this->assertDatabaseCount('product_prices', 1);

    $response = $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => $variant->name,
        'stock' => $variant->stock,
        'reject_stock' => $variant->reject_stock,
        'retail_stock' => $variant->retail_stock,
        'photo_keys' => ['product-variant/test.jpg'],
        'prices' => allPriceTypes(),
    ]);

    $response->assertRedirect();
    $this->assertDatabaseCount('product_prices', 9);
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => '',
        'stock' => 100,
        'reject_stock' => 10,
        'retail_stock' => 20,
        'photo_keys' => ['product-variant/test.jpg'],
        'prices' => allPriceTypes(),
    ]);

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

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => 'Test',
        'stock' => 100,
        'reject_stock' => 10,
        'retail_stock' => 20,
        'photo_keys' => ['product-variant/test.jpg'],
        'prices' => [
            ['type' => 'retail', 'price' => 10000],
        ],
    ]);

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

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

test('guest cannot delete variant', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->delete(route('admin.master.products.variants.destroy', [$product, $variant]));
    $response->assertRedirect(route('login'));
    $this->assertDatabaseHas('product_variants', ['id' => $variant->id, 'deleted_at' => null]);
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->delete(route('admin.master.products.variants.destroy', [$product, $variant]));
    $response->assertRedirect();
    $this->assertSoftDeleted('product_variants', ['id' => $variant->id]);
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    ProductPrice::create([
        'variant_id' => $variant->id,
        'type' => 'retail',
        'price' => 10000,
    ]);
    ProductPrice::create([
        'variant_id' => $variant->id,
        'type' => 'wholesale',
        'price' => 8000,
    ]);

    $this->assertDatabaseCount('product_prices', 2);

    $response = $this->delete(route('admin.master.products.variants.destroy', [$product, $variant]));
    $response->assertRedirect();
    $this->assertDatabaseCount('product_prices', 0);
});

test('delete variant does not affect other variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant1 = ProductVariant::factory()->for($product)->create(['name' => 'Keep']);
    $variant2 = ProductVariant::factory()->for($product)->create(['name' => 'Delete']);

    ProductPrice::create([
        'variant_id' => $variant1->id,
        'type' => 'retail',
        'price' => 10000,
    ]);
    ProductPrice::create([
        'variant_id' => $variant2->id,
        'type' => 'retail',
        'price' => 15000,
    ]);

    $response = $this->delete(route('admin.master.products.variants.destroy', [$product, $variant2]));
    $response->assertRedirect();

    $this->assertDatabaseHas('product_variants', ['id' => $variant1->id, 'name' => 'Keep', 'deleted_at' => null]);
    $this->assertDatabaseHas('product_prices', ['variant_id' => $variant1->id]);
});

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

    $product = Product::factory()->create();

    $response = $this->delete(route('admin.master.products.variants.destroy', [$product, 99999]));
    $response->assertStatus(404);
});

/*
|--------------------------------------------------------------------------
| TRANSFER STOCK (BAGUS -> ECER)
|--------------------------------------------------------------------------
*/

test('guest cannot transfer stock', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $response->assertRedirect(route('login'));
});

test('authenticated user can transfer stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create([
        'stock' => 100,
        'retail_stock' => 20,
    ]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $response->assertRedirect();
    $variant->refresh();
    expect($variant->stock)->toBe(90);
    expect($variant->retail_stock)->toBe(30);
});

test('transfer stock creates two stock mutation records', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100, 'retail_stock' => 20]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $this->assertDatabaseCount('stock_mutations', 2);

    $outMutation = StockMutation::where('stockable_id', $variant->id)->where('type', 'out')->first();
    expect($outMutation)->not->toBeNull();
    expect((float) $outMutation->quantity)->toBe(-10.0);
    expect((float) $outMutation->stock_before)->toBe(100.0);
    expect((float) $outMutation->stock_after)->toBe(90.0);
    expect($outMutation->stock_quality)->toBe('good');
    expect($outMutation->user_id)->toBe($user->id);

    $inMutation = StockMutation::where('stockable_id', $variant->id)->where('type', 'in')->first();
    expect($inMutation)->not->toBeNull();
    expect((float) $inMutation->quantity)->toBe(10.0);
    expect((float) $inMutation->stock_before)->toBe(20.0);
    expect((float) $inMutation->stock_after)->toBe(30.0);
    expect($inMutation->stock_quality)->toBe('retail');
    expect($inMutation->user_id)->toBe($user->id);
});

test('transfer stock with description saves to mutations', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 50, 'retail_stock' => 10]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 5,
        'description' => 'Transfer untuk display toko',
    ]);

    $mutation = StockMutation::where('stockable_id', $variant->id)->where('type', 'out')->first();
    expect($mutation->description)->toBe('Transfer untuk display toko');
});

test('transfer stock without description uses default', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 50, 'retail_stock' => 10]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 5,
    ]);

    $mutation = StockMutation::where('stockable_id', $variant->id)->where('type', 'out')->first();
    expect($mutation->description)->toBe('Transfer stok bagus ke stok ecer');
});

test('transfer stock quantity must be provided', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), []);

    $variant->refresh();
    expect($variant->stock)->toBe(100);
    $this->assertDatabaseCount('stock_mutations', 0);
});

test('transfer stock quantity must be integer', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 'abc',
    ]);

    $variant->refresh();
    expect($variant->stock)->toBe(100);
    $this->assertDatabaseCount('stock_mutations', 0);
});

test('transfer stock quantity must be at least 1', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 0,
    ]);

    $variant->refresh();
    expect($variant->stock)->toBe(100);
    $this->assertDatabaseCount('stock_mutations', 0);
});

test('transfer stock quantity cannot exceed available stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 10, 'retail_stock' => 5]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 15,
    ]);

    $variant->refresh();
    expect($variant->stock)->toBe(10);
    expect($variant->retail_stock)->toBe(5);
    $this->assertDatabaseCount('stock_mutations', 0);
});

test('transfer stock exactly equal to available stock is allowed', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 10, 'retail_stock' => 5]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $response->assertRedirect();
    $variant->refresh();
    expect($variant->stock)->toBe(0);
    expect($variant->retail_stock)->toBe(15);
});

test('transfer stock from zero stock is rejected', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 0, 'retail_stock' => 0]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 1,
    ]);

    $variant->refresh();
    expect($variant->stock)->toBe(0);
    expect($variant->retail_stock)->toBe(0);
    $this->assertDatabaseCount('stock_mutations', 0);
});

test('transfer stock multiple times sequentially', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100, 'retail_stock' => 0]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), ['quantity' => 20]);
    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), ['quantity' => 30]);
    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), ['quantity' => 10]);

    $variant->refresh();
    expect($variant->stock)->toBe(40);
    expect($variant->retail_stock)->toBe(60);
    $this->assertDatabaseCount('stock_mutations', 6);
});

test('transfer stock does not affect reject_stock', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create([
        'stock' => 100,
        'reject_stock' => 50,
        'retail_stock' => 10,
    ]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 25,
    ]);

    $variant->refresh();
    expect($variant->stock)->toBe(75);
    expect($variant->reject_stock)->toBe(50);
    expect($variant->retail_stock)->toBe(35);
});

test('transfer stock on non-existent variant returns 404', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, 99999]), [
        'quantity' => 10,
    ]);
    $response->assertStatus(404);
});

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

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $response = $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $response->assertRedirect(route('admin.master.products.index'));
});

/*
|--------------------------------------------------------------------------
| STOCK MUTATION AUDIT TRAIL
|--------------------------------------------------------------------------
*/

test('creating product with stock creates initial stock mutations', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Audit',
            'stock' => 50,
            'reject_stock' => 5,
            'retail_stock' => 10,
            'photo_keys' => ['product-variant/audit.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $variant = ProductVariant::where('name', 'Varian Audit')->first();

    $this->assertDatabaseCount('stock_mutations', 3);

    $goodMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'good')->first();
    expect($goodMutation)->not->toBeNull();
    expect($goodMutation->type)->toBe('in');
    expect((float) $goodMutation->quantity)->toBe(50.0);
    expect((float) $goodMutation->stock_before)->toBe(0.0);
    expect((float) $goodMutation->stock_after)->toBe(50.0);
    expect($goodMutation->description)->toBe('Stok awal saat pembuatan varian');

    $rejectMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'reject')->first();
    expect((float) $rejectMutation->quantity)->toBe(5.0);

    $retailMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'retail')->first();
    expect((float) $retailMutation->quantity)->toBe(10.0);
});

test('creating product with zero stock creates no mutations', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->post(route('admin.master.products.store'), makeValidProductPayload([
        'variants' => [[
            'name' => 'Varian Kosong',
            'stock' => 0,
            'reject_stock' => 0,
            'retail_stock' => 0,
            'photo_keys' => ['product-variant/empty.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $this->assertDatabaseCount('stock_mutations', 0);
});

test('updating variant stock creates adjustment mutations', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->for($product)->create([
        'name' => 'Original',
        'stock' => 100,
        'reject_stock' => 10,
        'retail_stock' => 20,
    ]);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => $product->name,
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => 'Original',
            'stock' => 120,
            'reject_stock' => 10,
            'retail_stock' => 25,
            'photo_keys' => ['product-variant/updated.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $goodMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'good')->first();
    expect($goodMutation)->not->toBeNull();
    expect($goodMutation->type)->toBe('in');
    expect((float) $goodMutation->quantity)->toBe(20.0);
    expect((float) $goodMutation->stock_before)->toBe(100.0);
    expect((float) $goodMutation->stock_after)->toBe(120.0);

    $retailMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'retail')->first();
    expect((float) $retailMutation->quantity)->toBe(5.0);
});

test('updating variant via single edit creates adjustment mutations', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create([
        'name' => 'Single Edit',
        'stock' => 80,
        'reject_stock' => 5,
        'retail_stock' => 15,
    ]);

    $this->put(route('admin.master.products.variants.update', [$product, $variant]), [
        'name' => 'Single Edit',
        'stock' => 70,
        'reject_stock' => 8,
        'retail_stock' => 15,
        'photo_keys' => ['product-variant/single-edit.jpg'],
        'prices' => allPriceTypes(),
    ]);

    $goodMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'good')->first();
    expect($goodMutation)->not->toBeNull();
    expect($goodMutation->type)->toBe('out');
    expect((float) $goodMutation->quantity)->toBe(-10.0);

    $rejectMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'reject')->first();
    expect((float) $rejectMutation->quantity)->toBe(3.0);

    $retailMutation = StockMutation::where('stockable_id', $variant->id)->where('stock_quality', 'retail')->first();
    expect($retailMutation)->toBeNull();
});

test('no mutation created when stock values unchanged', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $category = Category::factory()->create();
    DB::table('product_categories')->insert([
        'product_id' => $product->id,
        'category_id' => $category->id,
    ]);
    $variant = ProductVariant::factory()->for($product)->create([
        'name' => 'Unchanged',
        'stock' => 50,
        'reject_stock' => 10,
        'retail_stock' => 20,
    ]);
    foreach (allPriceTypes() as $price) {
        ProductPrice::factory()->create(['variant_id' => $variant->id, 'type' => $price['type'], 'price' => $price['price']]);
    }

    $this->put(route('admin.master.products.update', $product), makeValidProductPayload([
        'name' => 'Updated Name Only',
        'category_ids' => [$category->id],
        'variants' => [[
            'id' => $variant->id,
            'name' => 'Unchanged',
            'stock' => 50,
            'reject_stock' => 10,
            'retail_stock' => 20,
            'photo_keys' => ['product-variant/unchanged.jpg'],
            'prices' => allPriceTypes(),
        ]],
    ]));

    $this->assertDatabaseCount('stock_mutations', 0);
});

test('stock mutations record user who performed the action', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $mutation = StockMutation::where('stockable_id', $variant->id)->first();
    expect($mutation->user_id)->toBe($user->id);
});

/*
|--------------------------------------------------------------------------
| STOCK MUTATIONS PAGE
|--------------------------------------------------------------------------
*/

test('guest cannot access stock mutations page', function () {
    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant]));
    $response->assertRedirect(route('login'));
});

test('authenticated user can access stock mutations page', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create();

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant]));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/stock-mutations')
        ->has('mutations.data', 0)
        ->where('product.id', $product->id)
        ->where('variant.id', $variant->id)
    );
});

test('stock mutations page displays mutations for specific variant', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant = ProductVariant::factory()->for($product)->create(['stock' => 100]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant]), [
        'quantity' => 10,
    ]);

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant]));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/stock-mutations')
        ->has('mutations.data', 2)
    );
});

test('stock mutations page does not show mutations from other variants', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create();
    $variant1 = ProductVariant::factory()->for($product)->create(['stock' => 100]);
    $variant2 = ProductVariant::factory()->for($product)->create(['stock' => 50]);

    $this->post(route('admin.master.products.variants.transfer-stock', [$product, $variant1]), [
        'quantity' => 10,
    ]);

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant1]));
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/stock-mutations')
        ->has('mutations.data', 2)
    );

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant2]));
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/master/product/variant/stock-mutations')
        ->has('mutations.data', 0)
    );
});

test('stock mutations page shows correct product and variant info', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $product = Product::factory()->create(['name' => 'Produk Test']);
    $variant = ProductVariant::factory()->for($product)->create(['name' => 'Varian Test']);

    $response = $this->get(route('admin.master.products.variants.stock-mutations', [$product, $variant]));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('product.name', 'Produk Test')
        ->where('variant.name', 'Varian Test')
    );
});
