<?php

declare(strict_types=1);

namespace FreshCloud\Mail\Tests\ImapClient;

use Oscar\MailEngine\ImapClient\ImapClientInterface;
use FreshCloud\Mail\ImapClient\ImapCredentials;
use Oscar\MailEngine\ImapClient\InMemoryImapClient;
use FreshCloud\Mail\ImapClient\ImapException;
use FreshCloud\Mail\Log\Logger;
use PHPUnit\Framework\TestCase;

final class InMemoryImapClientTest extends TestCase
{
    private ImapClientInterface $client;
    private Logger $logger;

    protected function setUp(): void
    {
        $this->logger = $this->createMock(Logger::class);
        $this->client = new InMemoryImapClient($this->logger);
    }

    public function testConnect(): void
    {
        $creds = new ImapCredentials('localhost', 993, 'user', 'pass');
        $connection = $this->client->connect($creds);
        
        $this->assertEquals('connected', $connection->state);
        $this->assertNotEmpty($connection->capabilities);
    }

    public function testDisconnect(): void
    {
        $this->client->disconnect();
        $this->assertFalse($this->client->isConnected());
    }

    public function testLogin(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $result = $this->client->login('valid', 'valid');
        
        $this->assertTrue($result);
        $connection = $this->client->getConnection();
        $this->assertEquals('authenticated', $connection->state);
    }

    public function testSelect(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $connection = $this->client->select('INBOX');
        
        $this->assertEquals('selected', $connection->state);
        $this->assertEquals('INBOX', $connection->selectedFolder);
    }

    public function testList(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $folders = $this->client->list();
        
        $this->assertContains('INBOX', $folders);
        $this->assertContains('Drafts', $folders);
    }

    public function testFetch(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $this->client->select('INBOX');
        
        $items = 'BODY.PEEK[HEADER] BODY.PEEK[TEXT]';
        $messages = $this->client->fetch('1:3', $items);
        
        $this->assertArrayHasKey(1, $messages);
        $this->assertArrayHasKey(2, $messages);
        $this->assertArrayHasKey(3, $messages);
        
        $this->assertStringContainsString('Test Message 1', $messages[1]['BODY[HEADER]']);
        $this->assertStringContainsString('body of message 1', $messages[1]['BODY[TEXT]']);
    }

    public function testSearch(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $this->client->select('INBOX');
        
        $uids = $this->client->search(['UNSEEN']);
        $this->assertEquals([1, 2, 3], $uids);
    }

    public function testStore(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $this->client->select('INBOX');
        
        $modified = $this->client->store('1:3', '+FLAGS', '\Seen');
        $this->assertEquals([1, 2, 3], $modified);
    }

    public function testAppend(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $this->client->select('INBOX');
        
        $uid = $this->client->append('INBOX', 'Test message', ['\Seen']);
        $this->assertEquals('1', $uid);
    }

    public function testExpunge(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->login('valid', 'valid');
        $this->client->select('INBOX');
        
        $expunged = $this->client->expunge();
        $this->assertEquals([], $expunged);
    }

    public function testNoop(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $result = $this->client->noop();
        
        $this->assertTrue($result);
    }

    public function testIsConnected(): void
    {
        $this->assertFalse($this->client->isConnected());
        
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->assertTrue($this->client->isConnected());
    }

    public function testConnectionAfterDisconnect(): void
    {
        $this->client->connect(new ImapCredentials('localhost', 993, 'user', 'pass'));
        $this->client->disconnect();
        
        $connection = $this->client->getConnection();
        $this->assertEquals('disconnected', $connection->state);
    }
}
