<?php

namespace App\Tests\Insurance;

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

/**
 * Covers the tenant insurance contract management flow used by the redesigned
 * /admin/insurance-pricing page: create with contract dates + kind, edit those
 * fields, toggle فعال/غیرفعال, and list returning inactive contracts too.
 */
class TenantInsuranceContractApiTest extends ApiTestCase
{
    /** @return array{0: \App\Auth\Entity\User, 1: Insurance} */
    private function makeDoctorAndInsurance(InsuranceType $type = InsuranceType::Basic): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست بیمه');
        $this->em->persist($doctor);

        $insurance = new Insurance('بیمه ایران ' . random_int(1000, 9999), $type);
        $this->em->persist($insurance);
        $this->em->flush();

        return [$owner, $insurance];
    }

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

        $body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'         => $insurance->getId(),
            'coverage_percent'     => 70,
            'franchise_percent'    => 15,
            'annual_ceiling_rials' => 20_000_000,
            'effective_from'       => 1_700_000_000,
            'effective_to'         => 1_800_000_000,
            'kind'                 => 'supplementary',
        ]);

        $this->assertSame(201, $this->responseCode());
        $row = $body['data']['data'];
        $this->assertEquals(70.0, $row['coverage_percent']);
        $this->assertEquals(15.0, $row['franchise_percent']);
        $this->assertSame(20_000_000, $row['annual_ceiling_rials']);
        $this->assertSame(1_700_000_000, $row['effective_from']);
        $this->assertSame(1_800_000_000, $row['effective_to']);
        $this->assertSame('supplementary', $row['kind']);
        $this->assertTrue($row['is_active']);
    }

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

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

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

    public function testNegativeFranchiseOnEditIsRejected(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance(InsuranceType::Supplementary);
        $created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 80,
        ]);
        $uuid = $created['data']['data']['uuid'];

        $body = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, [
            'franchise_percent' => -5,
        ]);

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

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

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

        $this->assertSame(201, $this->responseCode());
        $this->assertSame('basic', $body['data']['data']['kind']);
    }

    public function testEditUpdatesDatesKindAndAmounts(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        $created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 40,
        ]);
        $uuid = $created['data']['data']['uuid'];

        $body = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, [
            'coverage_percent'     => 90,
            'franchise_percent'    => 20,
            'annual_ceiling_rials' => null,
            'effective_to'         => 1_900_000_000,
            'kind'                 => 'supplementary',
        ]);

        $this->assertSame(200, $this->responseCode());
        $this->assertEquals(90.0, $body['data']['data']['coverage_percent']);
        $this->assertEquals(20.0, $body['data']['data']['franchise_percent']);
        $this->assertNull($body['data']['data']['annual_ceiling_rials']);
        $this->assertSame(1_900_000_000, $body['data']['data']['effective_to']);
        $this->assertSame('supplementary', $body['data']['data']['kind']);
    }

    public function testToggleIsActiveDoesNotClobberEffectiveTo(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        $created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 60,
            'effective_to'     => 1_850_000_000,
        ]);
        $uuid = $created['data']['data']['uuid'];

        $off = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => false]);
        $this->assertFalse($off['data']['data']['is_active']);
        // Deactivating via the toggle must keep the user-set effective_to intact.
        $this->assertSame(1_850_000_000, $off['data']['data']['effective_to']);

        $on = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => true]);
        $this->assertTrue($on['data']['data']['is_active']);
    }

    public function testListReturnsInactiveContracts(): void
    {
        [$owner, $insurance] = $this->makeDoctorAndInsurance();
        $created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
            'insurance_id'     => $insurance->getId(),
            'coverage_percent' => 30,
        ]);
        $uuid = $created['data']['data']['uuid'];
        $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => false]);

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

        $rows = $body['data']['data'] ?? $body['data'];
        $found = array_filter($rows, fn ($r) => $r['uuid'] === $uuid);
        $this->assertCount(1, $found, 'inactive contract must still appear in the list');
        $this->assertFalse(array_values($found)[0]['is_active']);
    }
}
