<?php

use App\Livewire\Studio\Manage\Purchase\Create;
use App\Livewire\Studio\Manage\Purchase\Index;
use App\Models\Bottle;
use App\Models\Perfume;
use App\Models\Product;
use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\Warehouse;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

beforeEach(function () {
    $this->setupUser();

    $role = Role::firstOrCreate(['name' => 'Owner']);
    Permission::firstOrCreate(['name' => 'view purchase']);
    Permission::firstOrCreate(['name' => 'create purchase']);
    Permission::firstOrCreate(['name' => 'delete purchase']);
    $role->givePermissionTo(['view purchase', 'create purchase', 'delete purchase']);
    $this->user->assignRole($role);

    $this->warehouse = Warehouse::factory()->create();
});

it('renders the purchase index page', function () {
    $this->actingAs($this->user)
        ->get(route('studio.manage.purchase.index'))
        ->assertOk()
        ->assertSeeLivewire(Index::class);
});

it('renders the purchase create page', function () {
    $this->actingAs($this->user)
        ->get(route('studio.manage.purchase.create'))
        ->assertOk()
        ->assertSeeLivewire(Create::class);
});

it('can add a perfume to the cart', function () {
    $perfume = Perfume::factory()->create(['cost_price' => 50000]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.perfume_id', $perfume->id)
        ->set('form.quantity_perfume', '10')
        ->call('addItem', 'parfum')
        ->assertHasNoErrors();

    $this->assertDatabaseHas('purchase_items', [
        'user_id' => $this->user->id,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
        'quantity' => 10,
        'unit_price' => 50000,
        'purchase_id' => null,
    ]);
});

it('can add a product to the cart', function () {
    $product = Product::factory()->create(['cost_price' => 30000]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.product_id', $product->id)
        ->set('form.quantity_product', '5')
        ->call('addItem', 'produk')
        ->assertHasNoErrors();

    $this->assertDatabaseHas('purchase_items', [
        'user_id' => $this->user->id,
        'purchasable_type' => Product::class,
        'purchasable_id' => $product->id,
        'quantity' => 5,
        'unit_price' => 30000,
        'purchase_id' => null,
    ]);
});

it('can add a bottle to the cart', function () {
    $bottle = Bottle::factory()->create(['cost_price' => 5000]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.bottle_id', $bottle->id)
        ->set('form.quantity_bottle', '100')
        ->call('addItem', 'botol')
        ->assertHasNoErrors();

    $this->assertDatabaseHas('purchase_items', [
        'user_id' => $this->user->id,
        'purchasable_type' => Bottle::class,
        'purchasable_id' => $bottle->id,
        'quantity' => 100,
        'unit_price' => 5000,
        'purchase_id' => null,
    ]);
});

it('can update item quantity in the cart', function () {
    $perfume = Perfume::factory()->create(['cost_price' => 50000]);
    $item = PurchaseItem::factory()->create([
        'user_id' => $this->user->id,
        'purchase_id' => null,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
        'quantity' => 10,
        'unit_price' => 50000,
        'total_price' => 500000,
    ]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.item_id', $item->id)
        ->set('form.quantity_edit', '15')
        ->call('updateItem')
        ->assertHasNoErrors();

    $this->assertDatabaseHas('purchase_items', [
        'id' => $item->id,
        'quantity' => 15,
        'total_price' => 750000,
    ]);
});

it('can delete an item from the cart', function () {
    $perfume = Perfume::factory()->create();
    $item = PurchaseItem::factory()->create([
        'user_id' => $this->user->id,
        'purchase_id' => null,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
    ]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->call('deleteItem', $item->id)
        ->assertHasNoErrors();

    $this->assertSoftDeleted('purchase_items', ['id' => $item->id]);
});

it('can store a purchase and update warehouse stock', function () {
    $perfume = Perfume::factory()->create(['cost_price' => 100000]);
    PurchaseItem::factory()->create([
        'user_id' => $this->user->id,
        'purchase_id' => null,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
        'quantity' => 10,
        'unit_price' => 100000,
        'total_price' => 1000000,
    ]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.warehouse_id', $this->warehouse->id)
        ->set('form.purchase_date', now()->format('Y-m-d'))
        ->set('form.invoice_number', 'INV-001')
        ->call('save')
        ->assertHasNoErrors()
        ->assertRedirect(route('studio.manage.purchase.index', [
            'notification' => 'Belanja berhasil ditambahkan.',
        ]));

    $this->assertDatabaseHas('purchases', [
        'warehouse_id' => $this->warehouse->id,
        'invoice_number' => 'INV-001',
        'total' => 1000000,
    ]);

    // Check stock update
    $this->assertDatabaseHas('perfume_warehouse', [
        'warehouse_id' => $this->warehouse->id,
        'perfume_id' => $perfume->id,
        'stock' => 10,
    ]);
});

it('can store a purchase with image', function () {
    $perfume = Perfume::factory()->create(['cost_price' => 100000]);
    PurchaseItem::factory()->create([
        'user_id' => $this->user->id,
        'purchase_id' => null,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
        'quantity' => 10,
        'unit_price' => 100000,
        'total_price' => 1000000,
    ]);

    Storage::fake('public');
    $image = \Illuminate\Http\UploadedFile::fake()->image('invoice.jpg');

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.warehouse_id', $this->warehouse->id)
        ->set('form.purchase_date', now()->format('Y-m-d'))
        ->set('form.image', [[
            'name' => 'invoice.jpg',
            'path' => Storage::disk('public')->path($image->store('tmp', 'public')),
            'size' => $image->getSize(),
            'type' => $image->getMimeType(),
        ]])
        ->call('save')
        ->assertHasNoErrors();

    $purchase = Purchase::latest()->first();
    expect($purchase->getFirstMediaUrl('image'))->not->toBeEmpty();
});

it('cannot store a purchase with empty cart', function () {
    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->set('form.warehouse_id', $this->warehouse->id)
        ->set('form.purchase_date', now()->format('Y-m-d'))
        ->call('save')
        ->assertHasNoErrors(); // It shows a toast, doesn't redirect

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

it('validates required fields', function () {
    $perfume = Perfume::factory()->create();
    PurchaseItem::factory()->create([
        'user_id' => $this->user->id,
        'purchase_id' => null,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
    ]);

    Livewire::actingAs($this->user)
        ->test(Create::class)
        ->call('save')
        ->assertHasErrors([
            'form.warehouse_id' => 'required',
            'form.purchase_date' => 'required',
        ]);
});

it('can delete a purchase', function () {
    $perfume = Perfume::factory()->create();
    $purchase = Purchase::factory()->create([
        'warehouse_id' => $this->warehouse->id,
    ]);
    $item = PurchaseItem::factory()->create([
        'purchase_id' => $purchase->id,
        'purchasable_type' => Perfume::class,
        'purchasable_id' => $perfume->id,
        'quantity' => 10,
    ]);

    // Initial stock (assuming it was added when purchase was created)
    $this->warehouse->perfumes()->attach($perfume->id, ['stock' => 10]);

    Livewire::actingAs($this->user)
        ->test(Index::class)
        ->call('delete', $purchase->id)
        ->assertHasNoErrors();

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

    // Check stock was decreased
    $this->assertDatabaseMissing('perfume_warehouse', [
        'warehouse_id' => $this->warehouse->id,
        'perfume_id' => $perfume->id,
        'stock' => 10,
    ]);
});

it('cannot access purchase without permission', function () {
    $this->user->roles()->detach();
    $this->user->permissions()->detach();

    $this->actingAs($this->user)
        ->get(route('studio.manage.purchase.index'))
        ->assertForbidden();

    $this->actingAs($this->user)
        ->get(route('studio.manage.purchase.create'))
        ->assertForbidden();
});
