<?php

namespace App\Tests\Insurance;

use App\Doctor\Entity\Doctor;
use App\Insurance\Entity\Insurance;
use App\Insurance\Enum\InsuranceType;
use App\Insurance\Service\InsuranceCoverageDefaultService;
use App\Tests\ApiTestCase;

/**
 * Contract-level per-category coverage overrides over the tenant insurance API:
 * sending them stores an override, omitting them keeps the contract on the central
 * admin default (live fallback).
 */
class TenantInsuranceCategoryCoverageApiTest extends ApiTestCase
{
    /** @return array{0: \App\Auth\Entity\User, 1: Insurance} */
    private function makeDoctorAndInsurance(): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست پوشش نوع خدمت');
        $this->em->persist($doctor);

        $insurance = new Insurance('بیمه پایه ' . random_int(1000, 9999), InsuranceType::Basic);
        $this->em->persist($insurance);
        $this->em->flush();

        return [$owner, $insurance];
    }

    public function testContractWithoutOverridesFollowsTheAdminDefault(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
            ['key' => 'outpatient', 'coverage_percent' => 70],
            ['key' => 'inpatient',  'coverage_percent' => 30],
        ]);

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id' => $insurance->getId(),
        ]);

        $this->assertSame(201, $this->responseCode());
        $row = $body['data']['data'];
        $this->assertEquals(70.0, $row['category_coverages']['outpatient']);
        $this->assertEquals(30.0, $row['category_coverages']['inpatient']);
        $this->assertSame('admin_default', $row['category_coverage_source']['outpatient']);
    }

    public function testSendingCategoryCoveragesStoresAnOverride(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
            ['key' => 'outpatient', 'coverage_percent' => 70],
            ['key' => 'inpatient',  'coverage_percent' => 30],
        ]);

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [
                ['key' => 'inpatient', 'coverage_percent' => 90],
            ],
        ]);

        $this->assertSame(201, $this->responseCode());
        $row = $body['data']['data'];
        $this->assertEquals(90.0, $row['category_coverages']['inpatient']);
        $this->assertSame('override', $row['category_coverage_source']['inpatient']);
        $this->assertSame('admin_default', $row['category_coverage_source']['outpatient']);
    }

    public function testAnEnabledServiceKindCannotBeLeftWithoutAPercent(): void
    {
        // بدون پیش‌فرض مرکزی: ارسال درصد فقط برای سرپایی، بستری را صفر رها می‌کند.
        [$owner, $insurance] = $this->makeDoctorAndInsurance();

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [
                ['key' => 'outpatient', 'coverage_percent' => 70],
                ['key' => 'inpatient',  'coverage_percent' => null],
            ],
        ]);

        $this->assertSame(422, $this->responseCode());
        $this->assertSame('category_coverages', $body['errors'][0]['field']);
        $this->assertStringContainsString('خدمات بستری', $body['errors'][0]['message']);
    }

    public function testADisabledServiceKindNeedsNoPercent(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        $this->authJson('PUT', '/api/v1/insurance-pricing', $owner, [
            'service_categories' => [
                ['key' => 'outpatient', 'enabled' => true],
                ['key' => 'inpatient',  'enabled' => false],
            ],
        ]);

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [
                ['key' => 'outpatient', 'coverage_percent' => 70],
            ],
        ]);

        $this->assertSame(201, $this->responseCode());
        $this->assertEquals(70.0, $body['data']['data']['category_coverages']['outpatient']);
    }

    public function testListReturnsEffectivePercentsAndSources(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
            ['key' => 'outpatient', 'coverage_percent' => 55],
        ]);
        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, ['insurance_id' => $insurance->getId()]);

        $body = $this->authJson('GET', '/api/v1/billing/tenant-insurances', $owner);

        $this->assertSame(200, $this->responseCode());
        $row = $body['data']['data'][0];
        $this->assertEquals(55.0, $row['category_coverages']['outpatient']);
        $this->assertArrayHasKey('inpatient', $row['category_coverage_source']);
    }

    public function testUnknownCategoryIsRejected(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();

        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [['key' => 'dental', 'coverage_percent' => 50]],
        ]);

        $this->assertSame(422, $this->responseCode());
    }

    public function testPercentAbove100IsRejected(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();

        $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [['key' => 'outpatient', 'coverage_percent' => 101]],
        ]);

        $this->assertSame(422, $this->responseCode());
    }

    public function testPatchCanDropAnOverrideBackToTheAdminDefault(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        // سرپایی هم پیش‌فرض دارد، وگرنه ساخت قرارداد به‌خاطر «درصد پوشش الزامی است» رد می‌شود.
        static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
            ['key' => 'outpatient', 'coverage_percent' => 50],
            ['key' => 'inpatient',  'coverage_percent' => 30],
        ]);

        $created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'       => $insurance->getId(),
            'category_coverages' => [['key' => 'inpatient', 'coverage_percent' => 90]],
        ]);
        $uuid = $created['data']['data']['uuid'];

        $body = $this->authJson('PATCH', '/api/v1/billing/tenant-insurances/' . $uuid, $owner, [
            'category_coverages' => [['key' => 'inpatient', 'coverage_percent' => null]],
        ]);

        $this->assertSame(200, $this->responseCode());
        $row = $body['data']['data'];
        $this->assertEquals(30.0, $row['category_coverages']['inpatient']);
        $this->assertSame('admin_default', $row['category_coverage_source']['inpatient']);
    }
}
