<?php

namespace App\Tests\Entity;

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

class UserExtendedTest extends TestCase
{
    private function createUser(): User
    {
        $user = new User();
        $user->setEmail('test@test.com');
        $user->setFirstName('John');
        $user->setLastName('Doe');
        $user->setPassword('hashed');

        return $user;
    }

    public function testKeycloakId(): void
    {
        $user = $this->createUser();
        $this->assertNull($user->getKeycloakId());

        $user->setKeycloakId('kc-123');
        $this->assertSame('kc-123', $user->getKeycloakId());
    }

    public function testTempPassword(): void
    {
        $user = $this->createUser();
        $this->assertNull($user->getTempPassword());
        $this->assertFalse($user->hasTempPassword());

        $user->setTempPassword('temp123');
        $this->assertSame('temp123', $user->getTempPassword());
        $this->assertTrue($user->hasTempPassword());

        $user->setTempPassword(null);
        $this->assertFalse($user->hasTempPassword());
    }

    public function testGoogleAuthenticator(): void
    {
        $user = $this->createUser();

        $this->assertFalse($user->isGoogleAuthenticatorEnabled());
        $this->assertNull($user->getGoogleAuthenticatorSecret());
        $this->assertSame('test@test.com', $user->getGoogleAuthenticatorUsername());

        $user->setGoogleAuthenticatorSecret('ABCDEF');
        $user->setIsGoogleAuthEnabled(true);
        $this->assertTrue($user->isGoogleAuthenticatorEnabled());
        $this->assertSame('ABCDEF', $user->getGoogleAuthenticatorSecret());
    }

    public function testEmailAuth(): void
    {
        $user = $this->createUser();
        $this->assertFalse($user->isEmailAuthEnabled());
        $this->assertSame('test@test.com', $user->getEmailAuthRecipient());
        $this->assertNull($user->getEmailAuthCode());

        $user->setEmailAuthCode('123456');
        $this->assertSame('123456', $user->getEmailAuthCode());
    }

    public function testBackupCodes(): void
    {
        $user = $this->createUser();
        $this->assertSame([], $user->getBackupCodes());

        $codes = ['code1', 'code2', 'code3'];
        $user->setBackupCodes($codes);
        $this->assertSame($codes, $user->getBackupCodes());

        $this->assertTrue($user->isBackupCode('code1'));
        $this->assertFalse($user->isBackupCode('invalid'));

        $user->invalidateBackupCode('code1');
        $this->assertNotContains('code1', $user->getBackupCodes());
        $this->assertCount(2, $user->getBackupCodes());
    }

    public function testInvalidateBackupCodeWhenNull(): void
    {
        $user = $this->createUser();
        $ref = new \ReflectionProperty($user, 'backupCodes');
        $ref->setValue($user, null);

        $user->invalidateBackupCode('code1');
        $this->assertSame([], $user->getBackupCodes());
    }

    public function testAvatar(): void
    {
        $user = $this->createUser();
        $this->assertNull($user->getAvatar());

        $user->setAvatar('avatar.jpg');
        $this->assertSame('avatar.jpg', $user->getAvatar());
    }

    public function testAvatarFile(): void
    {
        $user = $this->createUser();
        $this->assertNull($user->getAvatarFile());

        $tmpFile = tempnam(sys_get_temp_dir(), 'avatar_');
        file_put_contents($tmpFile, 'fake');
        $file = new \Symfony\Component\HttpFoundation\File\File($tmpFile);

        $result = $user->setAvatarFile($file);
        $this->assertSame($file, $user->getAvatarFile());
        $this->assertSame($user, $result);

        $user->setAvatarFile(null);
        $this->assertNull($user->getAvatarFile());

        @unlink($tmpFile);
    }

    public function testFullName(): void
    {
        $user = $this->createUser();
        $this->assertSame('John Doe', $user->getFullName());
    }

    public function testRoles(): void
    {
        $user = $this->createUser();
        $this->assertContains('ROLE_USER', $user->getRoles());

        $user->setRoles(['ROLE_ROOT']);
        $this->assertContains('ROLE_ROOT', $user->getRoles());
        $this->assertContains('ROLE_USER', $user->getRoles());
    }

    public function testUserIdentifier(): void
    {
        $user = $this->createUser();
        $this->assertSame('test@test.com', $user->getUserIdentifier());
    }

    public function testSetIsEmailAuthEnabled(): void
    {
        $user = $this->createUser();
        $user->setIsEmailAuthEnabled(true);
        $this->assertTrue($user->isEmailAuthEnabled());

        $user->setKeycloakId('kc-123');
        $this->assertFalse($user->isEmailAuthEnabled());
    }

    public function testSetIsGoogleAuthEnabled(): void
    {
        $user = $this->createUser();
        $user->setIsGoogleAuthEnabled(true);
        $this->assertFalse($user->isGoogleAuthenticatorEnabled());
        $user->setGoogleAuthenticatorSecret('SECRET');
        $this->assertTrue($user->isGoogleAuthenticatorEnabled());
    }

    public function testClearTempPassword(): void
    {
        $user = $this->createUser();
        $user->setTempPassword('temp');
        $user->clearTempPassword();
        $this->assertFalse($user->hasTempPassword());
    }

    public function testGenerateBackupCodes(): void
    {
        $user = $this->createUser();
        $user->generateBackupCodes(5);
        $this->assertCount(5, $user->getBackupCodes());
    }

    public function testSerializeUnserialize(): void
    {
        $user = $this->createUser();
        $serialized = $user->__serialize();
        $this->assertArrayHasKey('id', $serialized);
        $this->assertArrayHasKey('email', $serialized);

        $newUser = new User();
        $newUser->__unserialize($serialized);
        $this->assertSame('test@test.com', $newUser->getEmail());
    }

    public function testCreatedAt(): void
    {
        $user = $this->createUser();
        $this->assertInstanceOf(\DateTimeImmutable::class, $user->getCreatedAt());
    }

    public function testUpdatedAt(): void
    {
        $user = $this->createUser();
        $this->assertNull($user->getUpdatedAt());
    }

    public function testEraseCredentials(): void
    {
        $user = $this->createUser();
        $user->eraseCredentials();
        $this->addToAssertionCount(1);
    }
}
