<?php

namespace App\Tests\Entity;

use App\Entity\User;
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function testNewUserHasCreatedAt(): void
    {
        $user = new User();

        self::assertInstanceOf(\DateTimeImmutable::class, $user->getCreatedAt());
    }

    public function testGetRolesAlwaysIncludesRoleUser(): void
    {
        $user = new User();

        self::assertContains('ROLE_USER', $user->getRoles());
    }

    public function testSetRolesDeduplicatesRoleUser(): void
    {
        $user = new User();
        $user->setRoles(['ROLE_ADMIN', 'ROLE_USER']);

        $roles = $user->getRoles();
        self::assertCount(2, $roles);
        self::assertContains('ROLE_ADMIN', $roles);
        self::assertContains('ROLE_USER', $roles);
    }

    public function testGetUserIdentifierReturnsEmail(): void
    {
        $user = new User();
        $user->setEmail('test@example.com');

        self::assertSame('test@example.com', $user->getUserIdentifier());
    }

    public function testFluentSetters(): void
    {
        $user = new User();

        $result = $user->setEmail('a@b.com')
            ->setFirstName('John')
            ->setLastName('Doe')
            ->setPassword('hashed');

        self::assertSame($user, $result);
        self::assertSame('a@b.com', $user->getEmail());
        self::assertSame('John', $user->getFirstName());
        self::assertSame('Doe', $user->getLastName());
        self::assertSame('hashed', $user->getPassword());
    }

    public function testOrganizerFields(): void
    {
        $user = new User();

        $result = $user->setCompanyName('Mon Asso')
            ->setSiret('12345678901234')
            ->setAddress('12 rue de la Paix')
            ->setPostalCode('75001')
            ->setCity('Paris')
            ->setPhone('0612345678');

        self::assertSame($user, $result);
        self::assertSame('Mon Asso', $user->getCompanyName());
        self::assertSame('12345678901234', $user->getSiret());
        self::assertSame('12 rue de la Paix', $user->getAddress());
        self::assertSame('75001', $user->getPostalCode());
        self::assertSame('Paris', $user->getCity());
        self::assertSame('0612345678', $user->getPhone());
    }

    public function testOrganizerFieldsDefaultToNull(): void
    {
        $user = new User();

        self::assertNull($user->getCompanyName());
        self::assertNull($user->getSiret());
        self::assertNull($user->getAddress());
        self::assertNull($user->getPostalCode());
        self::assertNull($user->getCity());
        self::assertNull($user->getPhone());
    }

    public function testLogoFields(): void
    {
        $user = new User();

        self::assertNull($user->getLogoFile());
        self::assertNull($user->getLogoName());
        self::assertNull($user->getUpdatedAt());

        $result = $user->setLogoName('logo.png');
        self::assertSame($user, $result);
        self::assertSame('logo.png', $user->getLogoName());

        $file = new \Symfony\Component\HttpFoundation\File\File(__FILE__);
        $result = $user->setLogoFile($file);
        self::assertSame($user, $result);
        self::assertSame($file, $user->getLogoFile());
        self::assertNotNull($user->getUpdatedAt());
    }

    public function testSetLogoFileNullDoesNotUpdateTimestamp(): void
    {
        $user = new User();
        $user->setLogoFile(null);

        self::assertNull($user->getUpdatedAt());
    }

    public function testResetCodeFields(): void
    {
        $user = new User();

        self::assertNull($user->getResetCode());
        self::assertNull($user->getResetCodeExpiresAt());

        $expiry = new \DateTimeImmutable('+15 minutes');
        $result = $user->setResetCode('123456')->setResetCodeExpiresAt($expiry);

        self::assertSame($user, $result);
        self::assertSame('123456', $user->getResetCode());
        self::assertSame($expiry, $user->getResetCodeExpiresAt());
    }

    public function testApprovalAndOfferFields(): void
    {
        $user = new User();

        self::assertFalse($user->isApproved());
        self::assertNull($user->getOffer());
        self::assertNull($user->getCommissionRate());

        $result = $user->setIsApproved(true)->setOffer('custom')->setCommissionRate(1.5);

        self::assertSame($user, $result);
        self::assertTrue($user->isApproved());
        self::assertSame('custom', $user->getOffer());
        self::assertSame(1.5, $user->getCommissionRate());
    }

    public function testSubAccountFields(): void
    {
        $parent = new User();
        $sub = new User();

        self::assertNull($sub->getParentOrganizer());
        self::assertNull($sub->getSubAccountPermissions());
        self::assertFalse($sub->hasPermission('scanner'));

        $result = $sub->setParentOrganizer($parent)
            ->setSubAccountPermissions(['scanner', 'events']);

        self::assertSame($sub, $result);
        self::assertSame($parent, $sub->getParentOrganizer());
        self::assertSame(['scanner', 'events'], $sub->getSubAccountPermissions());
        self::assertTrue($sub->hasPermission('scanner'));
        self::assertTrue($sub->hasPermission('events'));
        self::assertFalse($sub->hasPermission('tickets'));
    }

    public function testStripeFields(): void
    {
        $user = new User();

        self::assertNull($user->getStripeAccountId());
        self::assertNull($user->getStripeStatus());
        self::assertFalse($user->isStripeChargesEnabled());
        self::assertFalse($user->isStripePayoutsEnabled());

        $result = $user->setStripeAccountId('acct_1234567890')
            ->setStripeStatus('started')
            ->setStripeChargesEnabled(true)
            ->setStripePayoutsEnabled(true);

        self::assertSame($user, $result);
        self::assertSame('acct_1234567890', $user->getStripeAccountId());
        self::assertSame('started', $user->getStripeStatus());
        self::assertTrue($user->isStripeChargesEnabled());
        self::assertTrue($user->isStripePayoutsEnabled());
    }

    public function testBillingFields(): void
    {
        $user = new User();

        self::assertNull($user->isBilling());
        self::assertNull($user->getBillingAmount());
        self::assertNull($user->getBillingState());
        self::assertNull($user->getBillingStripeSubscriptionId());

        $result = $user->setIsBilling(true)
            ->setBillingAmount(2990)
            ->setBillingState('good')
            ->setBillingStripeSubscriptionId('sub_123456');

        self::assertSame($user, $result);
        self::assertTrue($user->isBilling());
        self::assertSame(2990, $user->getBillingAmount());
        self::assertSame('good', $user->getBillingState());
        self::assertSame('sub_123456', $user->getBillingStripeSubscriptionId());

        $user->setBillingState('suspendu');
        self::assertSame('suspendu', $user->getBillingState());
    }

    public function testDebtFields(): void
    {
        $user = new User();

        self::assertNull($user->getDebt());

        $result = $user->setDebt(5000);
        self::assertSame($user, $result);
        self::assertSame(5000, $user->getDebt());

        $user->addDebt(2000);
        self::assertSame(7000, $user->getDebt());

        $user->reduceDebt(3000);
        self::assertSame(4000, $user->getDebt());

        $user->reduceDebt(10000);
        self::assertSame(0, $user->getDebt());

        $user->setDebt(null);
        self::assertNull($user->getDebt());

        $user->addDebt(1000);
        self::assertSame(1000, $user->getDebt());
    }

    public function testEmailVerificationFields(): void
    {
        $user = new User();

        self::assertFalse($user->isVerified());
        self::assertNull($user->getEmailVerificationToken());
        self::assertNull($user->getEmailVerifiedAt());

        $now = new \DateTimeImmutable();
        $result = $user->setIsVerified(true)
            ->setEmailVerificationToken('abc123')
            ->setEmailVerifiedAt($now);

        self::assertSame($user, $result);
        self::assertTrue($user->isVerified());
        self::assertSame('abc123', $user->getEmailVerificationToken());
        self::assertSame($now, $user->getEmailVerifiedAt());
    }

    public function testEraseCredentialsDoesNotThrow(): void
    {
        $user = new User();
        $user->eraseCredentials();

        self::assertNull($user->getId());
    }

    public function testSuspendedFields(): void
    {
        $user = new User();

        self::assertNull($user->isSuspended());

        $result = $user->setIsSuspended(true);
        self::assertSame($user, $result);
        self::assertTrue($user->isSuspended());

        $user->setIsSuspended(false);
        self::assertFalse($user->isSuspended());

        $user->setIsSuspended(null);
        self::assertNull($user->isSuspended());
    }
}
