<?php

namespace App\Tests\Entity;

use App\Entity\BilletBuyer;
use App\Entity\BilletBuyerItem;
use App\Entity\Event;
use App\Entity\User;
use PHPUnit\Framework\TestCase;

class BilletBuyerTest extends TestCase
{
    public function testDefaults(): void
    {
        $buyer = new BilletBuyer();

        self::assertNull($buyer->getId());
        self::assertNull($buyer->getEvent());
        self::assertNull($buyer->getUser());
        self::assertNull($buyer->getFirstName());
        self::assertNull($buyer->getLastName());
        self::assertNull($buyer->getEmail());
        self::assertSame(0, $buyer->getTotalHT());
        self::assertSame(0.0, $buyer->getTotalHTDecimal());
        self::assertSame(BilletBuyer::STATUS_PENDING, $buyer->getStatus());
        self::assertNull($buyer->getStripeSessionId());
        self::assertNull($buyer->getPaymentMethod());
        self::assertNull($buyer->getCardBrand());
        self::assertNull($buyer->getCardLast4());
        self::assertNull($buyer->getPaidAt());
        self::assertMatchesRegularExpression('/^ETICKET-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $buyer->getReference());
        self::assertSame(32, \strlen($buyer->getAccessToken()));
        self::assertInstanceOf(\DateTimeImmutable::class, $buyer->getCreatedAt());
        self::assertCount(0, $buyer->getItems());
    }

    public function testSetAndGetEvent(): void
    {
        $buyer = new BilletBuyer();
        $event = new Event();
        $result = $buyer->setEvent($event);

        self::assertSame($event, $buyer->getEvent());
        self::assertSame($buyer, $result);
    }

    public function testSetAndGetUser(): void
    {
        $buyer = new BilletBuyer();
        $user = new User();
        $result = $buyer->setUser($user);

        self::assertSame($user, $buyer->getUser());
        self::assertSame($buyer, $result);

        $buyer->setUser(null);
        self::assertNull($buyer->getUser());
    }

    public function testSetAndGetNames(): void
    {
        $buyer = new BilletBuyer();
        $buyer->setFirstName('Jean');
        $buyer->setLastName('Dupont');
        $buyer->setEmail('jean@exemple.fr');

        self::assertSame('Jean', $buyer->getFirstName());
        self::assertSame('Dupont', $buyer->getLastName());
        self::assertSame('jean@exemple.fr', $buyer->getEmail());
    }

    public function testSetAndGetOrderNumber(): void
    {
        $buyer = new BilletBuyer();
        self::assertNull($buyer->getOrderNumber());

        $result = $buyer->setOrderNumber('2026-03-21-1');

        self::assertSame('2026-03-21-1', $buyer->getOrderNumber());
        self::assertSame($buyer, $result);
    }

    public function testSetAndGetTotalHT(): void
    {
        $buyer = new BilletBuyer();
        $result = $buyer->setTotalHT(2500);

        self::assertSame(2500, $buyer->getTotalHT());
        self::assertSame(25.0, $buyer->getTotalHTDecimal());
        self::assertSame($buyer, $result);
    }

    public function testSetAndGetStatus(): void
    {
        $buyer = new BilletBuyer();
        $result = $buyer->setStatus(BilletBuyer::STATUS_PAID);

        self::assertSame(BilletBuyer::STATUS_PAID, $buyer->getStatus());
        self::assertSame($buyer, $result);
    }

    public function testSetAndGetStripeSessionId(): void
    {
        $buyer = new BilletBuyer();
        $result = $buyer->setStripeSessionId('cs_test_123');

        self::assertSame('cs_test_123', $buyer->getStripeSessionId());
        self::assertSame($buyer, $result);
    }

    public function testSetAndGetPaymentDetails(): void
    {
        $buyer = new BilletBuyer();
        $buyer->setPaymentMethod('card');
        $buyer->setCardBrand('visa');
        $buyer->setCardLast4('4242');

        self::assertSame('card', $buyer->getPaymentMethod());
        self::assertSame('visa', $buyer->getCardBrand());
        self::assertSame('4242', $buyer->getCardLast4());
    }

    public function testSetAndGetIsInvitation(): void
    {
        $buyer = new BilletBuyer();
        self::assertNull($buyer->isInvitation());

        $result = $buyer->setIsInvitation(true);
        self::assertTrue($buyer->isInvitation());
        self::assertSame($buyer, $result);

        $buyer->setIsInvitation(false);
        self::assertFalse($buyer->isInvitation());

        $buyer->setIsInvitation(null);
        self::assertNull($buyer->isInvitation());
    }

    public function testSetAndGetPaidAt(): void
    {
        $buyer = new BilletBuyer();
        $date = new \DateTimeImmutable();
        $result = $buyer->setPaidAt($date);

        self::assertSame($date, $buyer->getPaidAt());
        self::assertSame($buyer, $result);
    }

    public function testAddItem(): void
    {
        $buyer = new BilletBuyer();
        $item = new BilletBuyerItem();
        $result = $buyer->addItem($item);

        self::assertCount(1, $buyer->getItems());
        self::assertSame($buyer, $item->getBilletBuyer());
        self::assertSame($buyer, $result);
    }

    public function testAddItemDoesNotDuplicate(): void
    {
        $buyer = new BilletBuyer();
        $item = new BilletBuyerItem();
        $buyer->addItem($item);
        $buyer->addItem($item);

        self::assertCount(1, $buyer->getItems());
    }

    public function testGenerateReferenceUnique(): void
    {
        $b1 = new BilletBuyer();
        $b2 = new BilletBuyer();

        self::assertNotSame($b1->getReference(), $b2->getReference());
    }

    public function testRefundedAmountDefaults(): void
    {
        $buyer = new BilletBuyer();

        self::assertSame(0, $buyer->getRefundedAmount());
        self::assertSame(0.0, $buyer->getRefundedAmountDecimal());
    }

    public function testSetAndGetRefundedAmount(): void
    {
        $buyer = new BilletBuyer();
        $result = $buyer->setRefundedAmount(1500);

        self::assertSame(1500, $buyer->getRefundedAmount());
        self::assertSame(15.0, $buyer->getRefundedAmountDecimal());
        self::assertSame($buyer, $result);
    }

    public function testStatusPartiallyRefunded(): void
    {
        $buyer = new BilletBuyer();
        $buyer->setStatus(BilletBuyer::STATUS_PARTIALLY_REFUNDED);

        self::assertSame('partially_refunded', $buyer->getStatus());
    }
}
