<?php

namespace App\Tests\Staff;

use App\Auth\Repository\UserRepository;
use App\Doctor\Entity\Doctor;
use App\Staff\Entity\ClinicStaff;
use App\Staff\Repository\ClinicStaffRepository;
use App\Staff\Service\StaffAccountService;
use App\Tests\ApiTestCase;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

/**
 * پرسنلِ دارای حساب باید مثل بقیهٔ نقش‌های پنل لاگین کند و محیط کاری‌اش را در
 * userinfo ببیند؛ پرسنل غیرفعال هیچ محیطی نمی‌گیرد.
 */
class StaffLoginContextTest extends ApiTestCase
{
    private function service(): StaffAccountService
    {
        return new StaffAccountService(
            static::getContainer()->get(UserRepository::class),
            static::getContainer()->get(ClinicStaffRepository::class),
            static::getContainer()->get(UserPasswordHasherInterface::class),
        );
    }

    /** @return array{0: Doctor, 1: ClinicStaff, 2: string} */
    private function staffWithAccount(bool $active = true): array
    {
        $ownerUser = $this->createUser(['ROLE_DOCTOR']);
        $doctor    = new Doctor($ownerUser, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        $staff = new ClinicStaff('doctor', $doctor->getId(), 'زهرا احمدی');
        $staff->setActive($active);
        $this->em->persist($staff);
        $this->em->flush();

        $mobile = '0912' . str_pad((string) random_int(0, 9_999_999), 7, '0', STR_PAD_LEFT);
        $this->service()->attachAccount($staff, $mobile, 'Staff@1234', $ownerUser);

        return [$doctor, $staff, $mobile];
    }

    private function json(): array
    {
        return json_decode($this->client->getResponse()->getContent(), true);
    }

    public function testStaffCanLogInAndSeesOwnEnvironment(): void
    {
        [$doctor, , $mobile] = $this->staffWithAccount();

        $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([
            'mobile_number' => $mobile,
            'password'      => 'Staff@1234',
        ]));

        self::assertSame(200, $this->client->getResponse()->getStatusCode());
        $token = $this->json()['access_token'] ?? null;
        self::assertNotNull($token);

        $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]);
        self::assertSame(200, $this->client->getResponse()->getStatusCode());

        $data = $this->json()['data'];
        self::assertSame('staff', $data['primary_role']);

        $staffContexts = array_values(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff'));
        self::assertCount(1, $staffContexts);
        self::assertSame($doctor->getUuid(), $staffContexts[0]['db_uuid']);
        self::assertTrue($staffContexts[0]['permissions']['resources']['services']['view']);
        self::assertArrayNotHasKey('patients', $staffContexts[0]['permissions']['resources']);
    }

    /** پرسنل غیرفعال: لاگین باز است ولی هیچ محیطی ندارد. */
    public function testInactiveStaffGetsNoContext(): void
    {
        [, , $mobile] = $this->staffWithAccount(active: false);

        $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([
            'mobile_number' => $mobile,
            'password'      => 'Staff@1234',
        ]));
        $token = $this->json()['access_token'] ?? null;
        self::assertNotNull($token);

        $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]);
        $data = $this->json()['data'];

        self::assertSame('staff', $data['primary_role']);
        self::assertSame([], array_values(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff')));
    }

    /** مرزی: منشی‌ای که پرسنل هم هست، نقش قوی‌ترش را نگه می‌دارد. */
    public function testSecretaryRoleWinsOverStaffRole(): void
    {
        [, $staff, $mobile] = $this->staffWithAccount();

        $user = static::getContainer()->get(UserRepository::class)->findByMobile($mobile);
        $user->addRole('ROLE_SECRETARY');
        $this->em->flush();

        $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([
            'mobile_number' => $mobile,
            'password'      => 'Staff@1234',
        ]));
        $token = $this->json()['access_token'];

        $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]);
        $data = $this->json()['data'];

        self::assertSame('secretary', $data['primary_role']);
        // محیطِ پرسنلی‌اش همچنان در فهرست هست
        self::assertNotEmpty(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff'));
        self::assertTrue($staff->hasAccount());
    }
}
