<?php

namespace App\Tests\Database;

use App\Appointment\Entity\DateOverride;
use App\Doctor\Entity\Doctor;
use App\Payment\Entity\Payment;
use App\Settlement\Entity\FinancialBreakdown;
use App\Tests\ApiTestCase;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;

/**
 * Business-key uniqueness: duplicate email / national_code / gateway_token,
 * a second date-override for the same (doctor, date), and a second financial
 * breakdown for the same (payment, source) must all be rejected at the DB.
 */
class UniqueConstraintsTest extends ApiTestCase
{
    public function testDuplicateEmailRejected(): void
    {
        $email = 'dup' . bin2hex(random_bytes(5)) . '@test.local';
        $this->createUser()->setEmail($email);
        $this->createUser()->setEmail($email);

        $this->expectException(UniqueConstraintViolationException::class);
        $this->em->flush();
    }

    public function testDuplicateGatewayTokenRejected(): void
    {
        $token = 'tok-' . bin2hex(random_bytes(6));
        $a = new Payment($this->createUser(), 1000, 'mellat', Payment::TYPE_SUBSCRIPTION);
        $a->setGatewayToken($token);
        $b = new Payment($this->createUser(), 1000, 'mellat', Payment::TYPE_SUBSCRIPTION);
        $b->setGatewayToken($token);
        $this->em->persist($a);
        $this->em->persist($b);

        $this->expectException(UniqueConstraintViolationException::class);
        $this->em->flush();
    }

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

        $date = time();
        $this->em->persist(new DateOverride($doctor, $date));
        $this->em->persist(new DateOverride($doctor, $date));

        $this->expectException(UniqueConstraintViolationException::class);
        $this->em->flush();
    }

    public function testDuplicateBreakdownPaymentSourceRejected(): void
    {
        $user    = $this->createUser();
        $payment = new Payment($user, 100_000, 'mellat', Payment::TYPE_APPOINTMENT);
        $this->em->persist($payment);
        $this->em->flush();

        $make = fn () => new FinancialBreakdown(
            $payment, FinancialBreakdown::SOURCE_APPOINTMENT, $user,
            100_000, 0, '0.00', 0, 100_000, '10.00', 10_000, 90_000, null, null, null,
        );
        $this->em->persist($make());
        $this->em->persist($make());

        $this->expectException(UniqueConstraintViolationException::class);
        $this->em->flush();
    }
}
