<?php

namespace App\Tests\Entity;

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

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

        return new Customer($user);
    }

    public function testConstructorDefaults(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Client suspendu.');

        $this->assertNull($log->getId());
        $this->assertSame(ActionLog::ACTION_SUSPEND_CUSTOMER, $log->getAction());
        $this->assertSame('Client suspendu.', $log->getMessage());
        $this->assertSame('info', $log->getSeverity());
        $this->assertTrue($log->isSuccess());
        $this->assertNull($log->getCustomer());
        $this->assertNull($log->getEntityId());
        $this->assertNull($log->getEntityType());
        $this->assertNull($log->getContext());
        $this->assertNull($log->getPreviousState());
        $this->assertNull($log->getNewState());
        $this->assertNull($log->getErrorMessage());
        $this->assertInstanceOf(\DateTimeImmutable::class, $log->getCreatedAt());
    }

    public function testConstructorWithAllArgs(): void
    {
        $log = new ActionLog(ActionLog::ACTION_FORMAL_NOTICE, 'Mise en demeure envoyée.', 'critical', false);

        $this->assertSame('critical', $log->getSeverity());
        $this->assertFalse($log->isSuccess());
    }

    public function testCustomer(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test');
        $this->assertNull($log->getCustomer());

        $customer = $this->createCustomer();
        $log->setCustomer($customer);
        $this->assertSame($customer, $log->getCustomer());

        $log->setCustomer(null);
        $this->assertNull($log->getCustomer());
    }

    public function testEntityIdAndType(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_WEBSITE, 'Test');

        $log->setEntityId(123);
        $this->assertSame(123, $log->getEntityId());

        $log->setEntityType('Website');
        $this->assertSame('Website', $log->getEntityType());

        $log->setEntityId(null);
        $this->assertNull($log->getEntityId());

        $log->setEntityType(null);
        $this->assertNull($log->getEntityType());
    }

    public function testContext(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test');
        $this->assertNull($log->getContext());

        $log->setContext('{"key":"value"}');
        $this->assertSame('{"key":"value"}', $log->getContext());

        $log->setContext(null);
        $this->assertNull($log->getContext());
    }

    public function testPreviousAndNewState(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test');

        $log->setPreviousState('active');
        $this->assertSame('active', $log->getPreviousState());

        $log->setNewState('suspended');
        $this->assertSame('suspended', $log->getNewState());

        $log->setPreviousState(null);
        $this->assertNull($log->getPreviousState());

        $log->setNewState(null);
        $this->assertNull($log->getNewState());
    }

    public function testSetErrorMessageSetsSuccessFalse(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test');
        $this->assertTrue($log->isSuccess());
        $this->assertNull($log->getErrorMessage());

        $log->setErrorMessage('Une erreur inattendue s\'est produite.');
        $this->assertSame("Une erreur inattendue s'est produite.", $log->getErrorMessage());
        $this->assertFalse($log->isSuccess());
    }

    public function testSetErrorMessageNull(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test', 'info', false);

        $log->setErrorMessage(null);
        $this->assertNull($log->getErrorMessage());
        // Setting null still sets success to false
        $this->assertFalse($log->isSuccess());
    }

    public function testActionConstants(): void
    {
        $this->assertSame('suspend_customer', ActionLog::ACTION_SUSPEND_CUSTOMER);
        $this->assertSame('unsuspend_customer', ActionLog::ACTION_UNSUSPEND_CUSTOMER);
        $this->assertSame('suspend_website', ActionLog::ACTION_SUSPEND_WEBSITE);
        $this->assertSame('unsuspend_website', ActionLog::ACTION_UNSUSPEND_WEBSITE);
        $this->assertSame('suspend_domain_email', ActionLog::ACTION_SUSPEND_DOMAIN_EMAIL);
        $this->assertSame('unsuspend_domain_email', ActionLog::ACTION_UNSUSPEND_DOMAIN_EMAIL);
        $this->assertSame('disable_customer', ActionLog::ACTION_DISABLE_CUSTOMER);
        $this->assertSame('delete_customer_data', ActionLog::ACTION_DELETE_CUSTOMER_DATA);
        $this->assertSame('formal_notice', ActionLog::ACTION_FORMAL_NOTICE);
        $this->assertSame('termination', ActionLog::ACTION_TERMINATION);
    }

    public function testSettersReturnStatic(): void
    {
        $log = new ActionLog(ActionLog::ACTION_SUSPEND_CUSTOMER, 'Test');

        $this->assertSame($log, $log->setCustomer(null));
        $this->assertSame($log, $log->setEntityId(1));
        $this->assertSame($log, $log->setEntityType('T'));
        $this->assertSame($log, $log->setContext('{}'));
        $this->assertSame($log, $log->setPreviousState('a'));
        $this->assertSame($log, $log->setNewState('b'));
        $this->assertSame($log, $log->setErrorMessage('err'));
    }
}
