<?php

namespace App\Tests\EventListener;

use App\Entity\Domain;
use App\Entity\DomainEmail;
use App\EventListener\DomainEmailSyncListener;
use App\Service\EsyMailService;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class DomainEmailSyncListenerTest extends TestCase
{
    private EsyMailService $esyMail;
    private LoggerInterface $logger;
    private DomainEmailSyncListener $listener;

    protected function setUp(): void
    {
        $this->esyMail = $this->createMock(EsyMailService::class);
        $this->logger = $this->createMock(LoggerInterface::class);
        $this->listener = new DomainEmailSyncListener($this->esyMail, $this->logger);
    }

    private function makeEmail(): DomainEmail
    {
        $domain = $this->createStub(Domain::class);
        $domain->method('getFqdn')->willReturn('example.com');

        $email = $this->createStub(DomainEmail::class);
        $email->method('getFullEmail')->willReturn('user@example.com');
        $email->method('getDomain')->willReturn($domain);
        $email->method('getName')->willReturn('User');
        $email->method('getQuotaMb')->willReturn(5120);
        $email->method('isActive')->willReturn(true);

        return $email;
    }

    // ── postPersist ──

    public function testPostPersistNotAvailable(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(false);
        $this->esyMail->expects($this->never())->method('createMailbox');

        $this->listener->postPersist($this->makeEmail());
    }

    public function testPostPersistCreatesDomainAndMailbox(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('domainExists')->willReturn(false);
        $this->esyMail->expects($this->once())->method('createDomain')->with('example.com');
        $this->esyMail->method('createMailbox')->willReturn(true);
        $this->logger->expects($this->once())->method('info');

        $this->listener->postPersist($this->makeEmail());
    }

    public function testPostPersistDomainAlreadyExists(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('domainExists')->willReturn(true);
        $this->esyMail->expects($this->never())->method('createDomain');
        $this->esyMail->method('createMailbox')->willReturn(true);

        $this->listener->postPersist($this->makeEmail());
    }

    public function testPostPersistMailboxCreationFails(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('domainExists')->willReturn(true);
        $this->esyMail->method('createMailbox')->willReturn(false);
        $this->logger->expects($this->never())->method('info');

        $this->listener->postPersist($this->makeEmail());
    }

    // ── postUpdate ──

    public function testPostUpdateNotAvailable(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(false);
        $this->esyMail->expects($this->never())->method('updateMailbox');

        $this->listener->postUpdate($this->makeEmail());
    }

    public function testPostUpdateMailboxNotExists(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('mailboxExists')->willReturn(false);
        $this->esyMail->expects($this->never())->method('updateMailbox');

        $this->listener->postUpdate($this->makeEmail());
    }

    public function testPostUpdateSuccess(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('mailboxExists')->willReturn(true);
        $this->esyMail->expects($this->once())->method('updateMailbox')->with('user@example.com', 'User', 5120, true);
        $this->logger->expects($this->once())->method('info');

        $this->listener->postUpdate($this->makeEmail());
    }

    // ── postRemove ──

    public function testPostRemoveNotAvailable(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(false);
        $this->esyMail->expects($this->never())->method('deleteMailbox');

        $this->listener->postRemove($this->makeEmail());
    }

    public function testPostRemoveSuccess(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('deleteMailbox')->willReturn(true);
        $this->logger->expects($this->once())->method('info');

        $this->listener->postRemove($this->makeEmail());
    }

    public function testPostRemoveDeleteFails(): void
    {
        $this->esyMail->method('isAvailable')->willReturn(true);
        $this->esyMail->method('deleteMailbox')->willReturn(false);
        $this->logger->expects($this->never())->method('info');

        $this->listener->postRemove($this->makeEmail());
    }
}
