<?php

declare(strict_types=1);

namespace App\Tests\Module\Sites\Domain\Entity;

use App\Module\Sites\Domain\Entity\Site;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

/**
 * Tests unitaires de comportement de l'entite Site : etat initial, setters,
 * gestion des timestamps et getter d'adresse complete. Les contraintes de
 * validation (regex, unicite) sont couvertes par SiteValidationTest.
 *
 * @internal
 */
final class SiteTest extends TestCase
{
    public function testConstructorInitialState(): void
    {
        $site = new Site(
            name: 'Chatellerault',
            street: "1 avenue de l'Europe",
            complement: null,
            postalCode: '86100',
            city: 'Chatellerault',
            color: '#056CF2',
        );

        self::assertNull($site->getId());
        self::assertSame('Chatellerault', $site->getName());
        self::assertSame("1 avenue de l'Europe", $site->getStreet());
        self::assertNull($site->getComplement());
        self::assertSame('86100', $site->getPostalCode());
        self::assertSame('Chatellerault', $site->getCity());
        self::assertSame('#056CF2', $site->getColor());
        self::assertInstanceOf(DateTimeImmutable::class, $site->getCreatedAt());
        self::assertInstanceOf(DateTimeImmutable::class, $site->getUpdatedAt());
    }

    public function testCreatedAtAndUpdatedAtAreInitiallyEqual(): void
    {
        $site = new Site('A', 'Rue X', null, '12345', 'B', '#000000');

        // A la creation, les deux timestamps sont seedes avec la meme valeur
        // pour garantir updated_at >= created_at au niveau base.
        self::assertEquals($site->getCreatedAt(), $site->getUpdatedAt());
    }

    public function testOnPreUpdateAdvancesUpdatedAtOnly(): void
    {
        $site              = new Site('A', 'Rue X', null, '12345', 'B', '#000000');
        $originalCreatedAt = $site->getCreatedAt();

        // On force updatedAt a une valeur strictement anterieure via reflection
        // pour ne pas dependre d'un `sleep()` (flaky en CI, lent) : l'entite
        // n'expose volontairement pas de setter sur updatedAt, c'est le
        // callback Doctrine PreUpdate qui s'en charge.
        $pastUpdatedAt     = new DateTimeImmutable('-1 hour');
        $reflection        = new ReflectionClass(Site::class);
        $updatedAtProperty = $reflection->getProperty('updatedAt');
        $updatedAtProperty->setValue($site, $pastUpdatedAt);

        $site->onPreUpdate();

        self::assertSame($originalCreatedAt, $site->getCreatedAt(), 'created_at doit rester immuable apres un update.');
        self::assertGreaterThan($pastUpdatedAt, $site->getUpdatedAt(), 'updated_at doit avancer apres onPreUpdate().');
    }

    public function testSettersMutateFields(): void
    {
        $site = new Site('Old', 'Old Street', null, '12345', 'OldCity', '#000000');

        $site->setName('New');
        $site->setStreet('New Street');
        $site->setComplement('Bat A');
        $site->setPostalCode('67890');
        $site->setCity('NewCity');
        $site->setColor('#ABCDEF');

        self::assertSame('New', $site->getName());
        self::assertSame('New Street', $site->getStreet());
        self::assertSame('Bat A', $site->getComplement());
        self::assertSame('67890', $site->getPostalCode());
        self::assertSame('NewCity', $site->getCity());
        self::assertSame('#ABCDEF', $site->getColor());
    }

    public function testFullAddressGetterWithoutComplement(): void
    {
        $site = new Site(
            name: 'Site1',
            street: '1 avenue de l\'Europe',
            complement: null,
            postalCode: '86100',
            city: 'Chatellerault',
            color: '#000000',
        );

        self::assertSame(
            "1 avenue de l'Europe\n86100 Chatellerault",
            $site->getFullAddress(),
        );
    }

    public function testFullAddressGetterWithComplement(): void
    {
        $site = new Site(
            name: 'Site2',
            street: '12 route de Poitiers',
            complement: 'Batiment B',
            postalCode: '86330',
            city: 'Saint-Jean-de-Sauves',
            color: '#000000',
        );

        self::assertSame(
            "12 route de Poitiers\nBatiment B\n86330 Saint-Jean-de-Sauves",
            $site->getFullAddress(),
        );
    }

    public function testFullAddressGetterIgnoresEmptyComplement(): void
    {
        // Garde defensive : un complement vide ou whitespace-only ne doit
        // pas creer une ligne vide visuellement disgracieuse.
        $site = new Site('S', 'Rue', '   ', '12345', 'Ville', '#000000');

        self::assertSame("Rue\n12345 Ville", $site->getFullAddress());
    }
}
