<?php

namespace App\Tests\Inventory;

use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;

/**
 * Per-tenant inventory CRUD (items + packages), scoped to the caller's doctor
 * entity. Covers success, derived aggregates, validation, empty state and
 * cross-tenant isolation.
 */
class InventoryApiTest extends ApiTestCase
{
    private function doctorUser(): array
    {
        $user   = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($user, 'دکتر');
        $this->em->persist($doctor);
        $this->em->flush();
        return [$user, $doctor];
    }

    // ── Items ────────────────────────────────────────────────────────────────

    public function testItemCreateListUpdateDelete(): void
    {
        [$user] = $this->doctorUser();

        $created = $this->authJson('POST', '/api/v1/inventory-item', $user, [
            'name' => 'دستکش', 'unit' => 'عدد', 'price' => 250000, 'stock' => 150, 'alertThreshold' => 20,
        ]);
        self::assertSame(201, $this->responseCode());
        self::assertSame('دستکش', $created['data']['name']);
        self::assertSame('in_stock', $created['data']['status']);
        $uuid = $created['data']['uuid'];

        $list = $this->authJson('GET', '/api/v1/inventory-items', $user);
        self::assertSame(200, $this->responseCode());
        self::assertCount(1, $list['data']['items']);
        self::assertSame(1, $list['data']['stats']['total']);
        self::assertSame(1, $list['data']['stats']['inStock']);

        // drop stock below threshold → low_stock
        $this->authJson('PATCH', '/api/v1/inventory-item/' . $uuid, $user, ['stock' => 5]);
        self::assertSame(200, $this->responseCode());
        $afterPatch = $this->authJson('GET', '/api/v1/inventory-items', $user);
        self::assertSame('low_stock', $afterPatch['data']['items'][0]['status']);
        self::assertSame(1, $afterPatch['data']['stats']['low']);

        $this->authJson('DELETE', '/api/v1/inventory-item/' . $uuid, $user);
        self::assertSame(200, $this->responseCode());
        $after = $this->authJson('GET', '/api/v1/inventory-items', $user);
        self::assertCount(0, $after['data']['items']);
    }

    public function testStatusDerivation(): void
    {
        [$user] = $this->doctorUser();

        // zero stock → out_of_stock, regardless of threshold
        $out = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'تمام‌شده', 'stock' => 0, 'alertThreshold' => 5]);
        self::assertSame('out_of_stock', $out['data']['status']);

        // stock above threshold → in_stock
        $in = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'موجود', 'stock' => 100, 'alertThreshold' => 10]);
        self::assertSame('in_stock', $in['data']['status']);
    }

    public function testItemRejectsEmptyName(): void
    {
        [$user] = $this->doctorUser();
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => '']);
        self::assertSame(422, $this->responseCode());
    }

    public function testEmptyStateReturnsZeroStats(): void
    {
        [$user] = $this->doctorUser();
        $list = $this->authJson('GET', '/api/v1/inventory-items', $user);
        self::assertSame(200, $this->responseCode());
        self::assertCount(0, $list['data']['items']);
        self::assertSame(
            ['total' => 0, 'low' => 0, 'inStock' => 0, 'outOfStock' => 0],
            $list['data']['stats']
        );
    }

    public function testCategoriesReturnsDistinctUsedCategories(): void
    {
        [$user] = $this->doctorUser();
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'a', 'category' => 'دارو']);
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'b', 'category' => 'دارو']);
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'c', 'category' => 'لوازم آزمایشگاهی']);

        $cats = $this->authJson('GET', '/api/v1/inventory-categories', $user);
        self::assertSame(200, $this->responseCode());
        self::assertCount(2, $cats['data']);
        self::assertContains('دارو', $cats['data']);
        self::assertContains('لوازم آزمایشگاهی', $cats['data']);
    }

    public function testMetaReturnsUnitAndCategoryLists(): void
    {
        [$user] = $this->doctorUser();
        $meta = $this->authJson('GET', '/api/v1/inventory-meta', $user);
        self::assertSame(200, $this->responseCode());
        self::assertContains('عدد', $meta['data']['units']);
        self::assertContains('سی‌سی', $meta['data']['units']);
        self::assertContains('دارو', $meta['data']['categories']);
        self::assertContains('سایر', $meta['data']['categories']);
    }

    public function testCreateStoresValidUnitAndCategory(): void
    {
        [$user] = $this->doctorUser();
        $item = $this->authJson('POST', '/api/v1/inventory-item', $user, [
            'name' => 'سرنگ', 'unit' => 'بسته', 'category' => 'لوازم مصرفی و تزریقات',
        ]);
        self::assertSame(201, $this->responseCode());
        self::assertSame('بسته', $item['data']['unit']);
        self::assertSame('لوازم مصرفی و تزریقات', $item['data']['category']);
    }

    public function testCreateRejectsInvalidUnit(): void
    {
        [$user] = $this->doctorUser();
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'x', 'unit' => 'واحد‌جعلی']);
        self::assertSame(422, $this->responseCode());
    }

    public function testCreateRejectsInvalidCategory(): void
    {
        [$user] = $this->doctorUser();
        $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'x', 'category' => 'دسته‌جعلی']);
        self::assertSame(422, $this->responseCode());
    }

    public function testEmptyUnitFallsBackToDefault(): void
    {
        [$user] = $this->doctorUser();
        $item = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'x', 'unit' => '']);
        self::assertSame(201, $this->responseCode());
        self::assertSame('عدد', $item['data']['unit']);
    }

    public function testCannotTouchAnotherTenantsItem(): void
    {
        [$ownerA] = $this->doctorUser();
        $created  = $this->authJson('POST', '/api/v1/inventory-item', $ownerA, ['name' => 'مال A']);
        $uuid     = $created['data']['uuid'];

        [$ownerB] = $this->doctorUser();
        $this->authJson('PATCH', '/api/v1/inventory-item/' . $uuid, $ownerB, ['name' => 'دزدی']);
        self::assertSame(404, $this->responseCode());
        $this->authJson('DELETE', '/api/v1/inventory-item/' . $uuid, $ownerB);
        self::assertSame(404, $this->responseCode());
    }

    // ── Packages ─────────────────────────────────────────────────────────────

    public function testPackageCreateComputesTotalAndAvailability(): void
    {
        [$user] = $this->doctorUser();

        $gel   = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'ژل', 'price' => 1200000, 'stock' => 10])['data']['uuid'];
        $glove = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'دستکش', 'price' => 500000, 'stock' => 1])['data']['uuid'];

        // 2×ژل (stock 10, ok) + 3×دستکش (stock 1, NOT enough) → unavailable
        $pkg = $this->authJson('POST', '/api/v1/inventory-package', $user, [
            'title' => 'پکیج یک',
            'items' => [
                ['itemUuid' => $gel,   'amount' => 2],
                ['itemUuid' => $glove, 'amount' => 3],
            ],
        ]);
        self::assertSame(201, $this->responseCode());
        self::assertSame(2 * 1200000 + 3 * 500000, $pkg['data']['total']);
        self::assertFalse($pkg['data']['available']);
        self::assertCount(2, $pkg['data']['items']);

        // list reflects the same package
        $list = $this->authJson('GET', '/api/v1/inventory-packages', $user);
        self::assertCount(1, $list['data']);
        self::assertSame('پکیج یک', $list['data'][0]['title']);
    }

    public function testPackageUpdateReplacesItemsAndDelete(): void
    {
        [$user] = $this->doctorUser();
        $a = $this->authJson('POST', '/api/v1/inventory-item', $user, ['name' => 'A', 'price' => 1000, 'stock' => 50])['data']['uuid'];

        $uuid = $this->authJson('POST', '/api/v1/inventory-package', $user, [
            'title' => 'p', 'items' => [['itemUuid' => $a, 'amount' => 1]],
        ])['data']['uuid'];

        $updated = $this->authJson('PATCH', '/api/v1/inventory-package/' . $uuid, $user, [
            'title' => 'p2', 'items' => [['itemUuid' => $a, 'amount' => 5]],
        ]);
        self::assertSame(200, $this->responseCode());
        self::assertSame('p2', $updated['data']['title']);
        self::assertCount(1, $updated['data']['items']);
        self::assertSame(5, $updated['data']['items'][0]['amount']);
        self::assertSame(5000, $updated['data']['total']);

        $this->authJson('DELETE', '/api/v1/inventory-package/' . $uuid, $user);
        self::assertSame(200, $this->responseCode());
        $after = $this->authJson('GET', '/api/v1/inventory-packages', $user);
        self::assertCount(0, $after['data']);
    }

    public function testPackageSkipsForeignItemReferences(): void
    {
        [$ownerA] = $this->doctorUser();
        $foreign  = $this->authJson('POST', '/api/v1/inventory-item', $ownerA, ['name' => 'خارجی', 'price' => 999, 'stock' => 5])['data']['uuid'];

        [$ownerB] = $this->doctorUser();
        $mine     = $this->authJson('POST', '/api/v1/inventory-item', $ownerB, ['name' => 'مال من', 'price' => 100, 'stock' => 5])['data']['uuid'];

        // package for B referencing A's item → foreign line dropped, only B's stays
        $pkg = $this->authJson('POST', '/api/v1/inventory-package', $ownerB, [
            'title' => 'mix',
            'items' => [
                ['itemUuid' => $foreign, 'amount' => 1],
                ['itemUuid' => $mine,    'amount' => 2],
            ],
        ]);
        self::assertSame(201, $this->responseCode());
        self::assertCount(1, $pkg['data']['items']);
        self::assertSame($mine, $pkg['data']['items'][0]['itemUuid']);
        self::assertSame(200, $pkg['data']['total']);
    }

    public function testPackageRejectsEmptyTitle(): void
    {
        [$user] = $this->doctorUser();
        $this->authJson('POST', '/api/v1/inventory-package', $user, ['title' => '']);
        self::assertSame(422, $this->responseCode());
    }
}
