<?php

namespace App\Tests\Shared;

use App\Auth\Entity\User;
use App\Doctor\Entity\Doctor;
use App\Secretary\Entity\DoctorSecretary;
use App\Shared\Util\PersianText;
use App\Tests\ApiTestCase;

/**
 * Persian/Arabic digits sent by any client must never reach the database.
 * The admin SPA normalizes at the input, but nobat724_front and clinic-pro-tauri
 * hit the same endpoints, so the request layer is the real guarantee.
 */
class NumericFieldNormalizerTest extends ApiTestCase
{
    private function toPersianDigits(string $latin): string
    {
        return str_replace(range('0', '9'), ['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'], $latin);
    }

    public function testDigitsHelperTranslatesWithoutStripping(): void
    {
        self::assertSame('09123456789', PersianText::digits('۰۹۱۲۳۴۵۶۷۸۹'));
        self::assertSame('0912', PersianText::digits('٠٩١٢'));
        self::assertSame('IR12-34', PersianText::digits('IR۱۲-۳۴'), 'letters and separators survive');
        self::assertSame('', PersianText::digits(''));
    }

    public function testSecretaryCreatedWithPersianDigitsIsStoredLatin(): void
    {
        $owner    = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']);
        $doctor   = new Doctor($owner, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        // db_test پاک نمی‌شود؛ شماره باید تازه باشد وگرنه endpoint با «تکراری» رد می‌کند.
        //
        // padding حتماً روی رقم لاتین انجام می‌شود و بعد تبدیل: `str_pad` بایتی است و
        // با نویسهٔ سه‌بایتیِ «۰» عددِ کوتاه را به بایت‌های نیمه‌کاره می‌شکست. چون طول
        // عدد تصادفی است، این تست گاهی سبز و گاهی ۴۲۲ می‌داد.
        do {
            $latinMobile   = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
            $persianMobile = $this->toPersianDigits($latinMobile);
        } while ($this->em->getRepository(User::class)->findOneBy(['mobileNumber' => $latinMobile]) !== null);

        // کد ملی هم همین‌طور. ثابت‌بودنش این تست را flaky می‌کرد: در اجرای کامل سوئیت،
        // بسته به ترتیب اجرا، ردیفِ اجرای قبلی باعث ۴۲۲ «تکراری» می‌شد و در اجرای تنها
        // سبز بود.
        // مثل شماره، یکتایی‌اش هم باید سنجیده شود: تصادفی‌بودن تنهایی کافی نیست و در
        // اجرای کامل سوئیت روی db_testِ انباشته، برخورد ۴۲۲ «تکراری» می‌داد.
        do {
            $latinNationalCode   = str_pad((string) random_int(0, 9_999_999_999), 10, '0', STR_PAD_LEFT);
            $persianNationalCode = $this->toPersianDigits($latinNationalCode);
        } while (
            $this->em->getRepository(DoctorSecretary::class)
                ->findOneBy(['nationalCode' => $latinNationalCode]) !== null
        );

        $body = $this->authJson('POST', '/api/v1/secretary', $owner, [
            'doctor_uuid'   => $doctor->getUuid(),
            'mobile_number' => $persianMobile,
            'name'          => 'منشی تست',
            'national_code' => $persianNationalCode,
        ]);

        // بدنه در پیام می‌آید: «۴۲۲ به‌جای ۲۰۱» بدون دلیلِ سرور قابل دیباگ نیست.
        self::assertSame(
            201,
            $this->responseCode(),
            'Persian digits must not break validation: ' . json_encode($body, JSON_UNESCAPED_UNICODE),
        );

        $this->em->clear();
        $created = $this->em->getRepository(User::class)->findOneBy(['mobileNumber' => $latinMobile]);
        self::assertNotNull($created, 'user is stored under the latin mobile');

        $rel = $this->em->getRepository(DoctorSecretary::class)->findOneBy(['secretary' => $created]);
        self::assertSame(PersianText::digits($persianNationalCode), $rel->getNationalCode());
    }

    public function testNestedArraysAreNormalized(): void
    {
        $user = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']);

        $this->authJson('PUT', '/api/v1/insurance-pricing', $user, [
            'free_visit_price_rials' => '۵۰۰۰۰۰',
            'insurances'             => [
                ['insurance_id' => 1, 'patient_share_rials' => '۱۲۳۴۵'],
            ],
        ]);

        // پروفایل پزشک ممکن است بیمه‌ای نداشته باشد؛ مهم این است که ارقام فارسی
        // باعث خطای اعتبارسنجی یا NaN نشوند.
        self::assertNotSame(500, $this->responseCode(), 'nested persian digits must not blow up');
    }

    public function testNonNumericKeysKeepPersianDigits(): void
    {
        $owner  = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        $mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);

        $this->authJson('POST', '/api/v1/secretary', $owner, [
            'doctor_uuid'   => $doctor->getUuid(),
            'mobile_number' => $mobile,
            'name'          => 'منشی شماره ۲',
        ]);
        self::assertSame(201, $this->responseCode());

        $this->em->clear();
        $created = $this->em->getRepository(User::class)->findOneBy(['mobileNumber' => $mobile]);
        self::assertStringContainsString('۲', $created->getRealName(), 'name is not a numeric field');
    }
}
