<?php

namespace Tests\Feature;

use App\Models\Product;
use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\Supplier;
use App\Models\User;
use App\Models\Warehouse;
use App\Notifications\PurchaseStatusNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class PartialReceiveNotificationTest extends TestCase
{
    use RefreshDatabase;

    private function scaffold(int $qtyOrdered): array
    {
        Role::firstOrCreate(['name' => 'supplier', 'guard_name' => 'web']);
        Role::firstOrCreate(['name' => 'manager', 'guard_name' => 'web']);

        $supplierUser = User::factory()->create();
        $supplierUser->assignRole('supplier');

        $supplier = Supplier::create([
            'code' => 'SUP-001', 'name' => 'PT Sumber Jaya',
            'user_id' => $supplierUser->id, 'is_active' => true,
        ]);

        $warehouse = Warehouse::create(['code' => 'WH-01', 'name' => 'Gudang Utama', 'is_active' => true]);

        $product = Product::create(['sku' => 'SKU-001', 'name' => 'Barang A']);

        $manager = User::factory()->create();
        $manager->assignRole('manager');

        $purchase = Purchase::create([
            'po_number' => 'PO-0001', 'supplier_name' => $supplier->name,
            'supplier_id' => $supplier->id, 'user_id' => $manager->id,
            'warehouse_id' => $warehouse->id, 'status' => 'shipped', 'total' => 0,
        ]);

        $item = PurchaseItem::create([
            'purchase_id' => $purchase->id, 'product_id' => $product->id,
            'sku' => $product->sku, 'product_name' => $product->name,
            'qty_ordered' => $qtyOrdered, 'qty_received' => 0,
            'unit_price' => 1000, 'subtotal' => 1000 * $qtyOrdered,
        ]);

        return compact('manager', 'supplierUser', 'purchase', 'item');
    }

    public function test_partial_receive_notifies_supplier_with_shortage_qty(): void
    {
        ['manager' => $manager, 'supplierUser' => $supplierUser, 'purchase' => $purchase, 'item' => $item]
            = $this->scaffold(qtyOrdered: 10);

        Notification::fake();

        // Receive only 6 of 10 → shortage of 4.
        $response = $this->actingAs($manager, 'sanctum')
            ->patchJson("/api/purchases/{$purchase->id}/receive", [
                'items' => [['id' => $item->id, 'qty_received' => 6]],
            ]);

        $response->assertOk();
        $this->assertSame('partial', $purchase->fresh()->status);

        Notification::assertSentTo(
            $supplierUser,
            PurchaseStatusNotification::class,
            function (PurchaseStatusNotification $notification) use ($supplierUser) {
                $data = $notification->toArray($supplierUser);

                return $data['status'] === 'partial'
                    && str_contains($data['message'], 'kurang 4 unit')
                    && str_contains($data['message'], 'follow up');
            }
        );
    }

    public function test_full_receive_notifies_supplier_without_followup_phrase(): void
    {
        ['manager' => $manager, 'supplierUser' => $supplierUser, 'purchase' => $purchase, 'item' => $item]
            = $this->scaffold(qtyOrdered: 10);

        Notification::fake();

        $response = $this->actingAs($manager, 'sanctum')
            ->patchJson("/api/purchases/{$purchase->id}/receive", [
                'items' => [['id' => $item->id, 'qty_received' => 10]],
            ]);

        $response->assertOk();
        $this->assertSame('received', $purchase->fresh()->status);

        Notification::assertSentTo(
            $supplierUser,
            PurchaseStatusNotification::class,
            function (PurchaseStatusNotification $notification) use ($supplierUser) {
                $data = $notification->toArray($supplierUser);

                return $data['status'] === 'received'
                    && ! str_contains($data['message'], 'follow up');
            }
        );
    }
}
