<?php

namespace App\Tests\Branch;

use App\Branch\Entity\Room;

class RoomCrudTest extends BranchTestCase
{
    /** @param array<string, mixed> $body */
    private function createRoom(\App\Auth\Entity\User $user, string $addressUuid, array $body = []): array
    {
        return $this->authJson('POST', '/api/v1/room', $user, $body + [
            'address_uuid' => $addressUuid,
            'name'         => 'اتاق تزریق',
        ]);
    }

    public function testRoomIsCreatedWithTenantPairDerivedFromTheBranch(): void
    {
        [$clinicUser, $clinic, $address] = $this->clinicWithAddress();

        $body = $this->createRoom($clinicUser, $address->getUuid(), ['capacity' => 3, 'floor' => '2']);

        self::assertSame(201, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
        self::assertSame(3, $body['data']['capacity']);
        self::assertSame('2', $body['data']['floor']);
        self::assertSame($address->getUuid(), $body['data']['address_uuid']);

        $room = $this->em->getRepository(Room::class)->findOneBy(['uuid' => $body['data']['uuid']]);
        self::assertSame('clinic', $room->getEntityType());
        self::assertSame($clinic->getId(), $room->getEntityId());
    }

    public function testPersonalBranchRoomBelongsToTheDoctor(): void
    {
        [$doctorUser, $doctor, $address] = $this->doctorWithAddress();

        $body = $this->createRoom($doctorUser, $address->getUuid());

        self::assertSame(201, $this->responseCode());

        $room = $this->em->getRepository(Room::class)->findOneBy(['uuid' => $body['data']['uuid']]);
        self::assertSame('doctor', $room->getEntityType());
        self::assertSame($doctor->getId(), $room->getEntityId());
    }

    public function testCapacityDefaultsToOne(): void
    {
        [$user, , $address] = $this->doctorWithAddress();

        $body = $this->createRoom($user, $address->getUuid());

        self::assertSame(1, $body['data']['capacity']);
        self::assertTrue($body['data']['active']);
    }

    public function testZeroCapacityIsRejected(): void
    {
        [$user, , $address] = $this->doctorWithAddress();

        $body = $this->createRoom($user, $address->getUuid(), ['capacity' => 0]);

        self::assertSame(422, $this->responseCode());
        self::assertSame('capacity', $body['errors'][0]['field']);
    }

    public function testBlankNameIsRejected(): void
    {
        [$user, , $address] = $this->doctorWithAddress();

        $body = $this->authJson('POST', '/api/v1/room', $user, [
            'address_uuid' => $address->getUuid(),
            'name'         => '   ',
        ]);

        self::assertSame(422, $this->responseCode());
        self::assertSame('name', $body['errors'][0]['field']);
    }

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

        $body = $this->authJson('POST', '/api/v1/room', $user, ['name' => 'اتاق']);

        self::assertSame(422, $this->responseCode());
        self::assertSame('address_uuid', $body['errors'][0]['field']);
    }

    /** جفت محیط از آدرس می‌آید، پس نمی‌شود اتاق را روی شعبهٔ محیط دیگر نشاند. */
    public function testRoomCannotBeCreatedOnAForeignBranch(): void
    {
        [$doctorUser] = $this->doctorWithAddress();
        [, , $foreignAddress] = $this->clinicWithAddress();

        $this->createRoom($doctorUser, $foreignAddress->getUuid());

        self::assertSame(404, $this->responseCode());
    }

    public function testRoomIsUpdated(): void
    {
        [$user, , $address] = $this->doctorWithAddress();
        $created = $this->createRoom($user, $address->getUuid());

        $body = $this->authJson('PATCH', "/api/v1/room/{$created['data']['uuid']}", $user, [
            'name'      => 'اتاق پانسمان',
            'capacity'  => 2,
            'room_type' => 'پانسمان',
            'active'    => false,
        ]);

        self::assertSame(200, $this->responseCode());
        self::assertSame('اتاق پانسمان', $body['data']['name']);
        self::assertSame(2, $body['data']['capacity']);
        self::assertSame('پانسمان', $body['data']['room_type']);
        self::assertFalse($body['data']['active']);
    }

    /** رشتهٔ خالی روی فیلد اختیاری یعنی «پاک کن»، نه ذخیرهٔ رشتهٔ خالی. */
    public function testBlankOptionalFieldBecomesNull(): void
    {
        [$user, , $address] = $this->doctorWithAddress();
        $created = $this->createRoom($user, $address->getUuid(), ['room_type' => 'تزریق']);

        $body = $this->authJson('PATCH', "/api/v1/room/{$created['data']['uuid']}", $user, ['room_type' => '']);

        self::assertNull($body['data']['room_type']);
    }

    public function testRoomIsDeleted(): void
    {
        [$user, , $address] = $this->doctorWithAddress();
        $created = $this->createRoom($user, $address->getUuid());

        $this->authJson('DELETE', "/api/v1/room/{$created['data']['uuid']}", $user);
        self::assertSame(200, $this->responseCode());

        $this->authJson('PATCH', "/api/v1/room/{$created['data']['uuid']}", $user, ['name' => 'x']);
        self::assertSame(404, $this->responseCode());
    }

    public function testForeignRoomIsNotFound(): void
    {
        [$clinicUser, , $clinicAddress] = $this->clinicWithAddress();
        $created = $this->createRoom($clinicUser, $clinicAddress->getUuid());

        [$doctorUser] = $this->doctorWithAddress();

        $this->authJson('PATCH', "/api/v1/room/{$created['data']['uuid']}", $doctorUser, ['name' => 'دزدیده‌شده']);
        self::assertSame(404, $this->responseCode());

        $this->authJson('DELETE', "/api/v1/room/{$created['data']['uuid']}", $doctorUser);
        self::assertSame(404, $this->responseCode());
    }

    public function testBranchRoomsAreListedForItsOwnerOnly(): void
    {
        [$user, , $address] = $this->doctorWithAddress();
        $this->createRoom($user, $address->getUuid(), ['name' => 'اتاق ۱']);
        $this->createRoom($user, $address->getUuid(), ['name' => 'اتاق ۲']);

        $body = $this->authJson('GET', "/api/v1/branch/{$address->getUuid()}/rooms", $user);

        self::assertSame(200, $this->responseCode());
        self::assertCount(2, $body['data']);

        [, , $foreignAddress] = $this->clinicWithAddress();
        $this->authJson('GET', "/api/v1/branch/{$foreignAddress->getUuid()}/rooms", $user);
        self::assertSame(404, $this->responseCode());
    }
}
