<?php

declare(strict_types=1);

namespace App\Framework\Mail\Testing;

use App\Framework\Mail\Message;
use App\Framework\Mail\TransportInterface;
use App\Framework\Mail\TransportResult;

final class MockTransport implements TransportInterface
{
    private array $sentMessages = [];

    private bool $shouldFail = false;

    private ?string $failureMessage = null;

    private bool $isAvailable = true;

    public function send(Message $message): TransportResult
    {
        if ($this->shouldFail) {
            return TransportResult::failure(
                error: $this->failureMessage ?? 'Mock transport failure',
                metadata: ['mock' => true]
            );
        }

        $generator = new \App\Framework\Ulid\UlidGenerator();
        $messageId = 'mock_' . $generator->generate();
        $this->sentMessages[] = [
            'message' => $message,
            'message_id' => $messageId,
            'sent_at' => new \DateTimeImmutable(),
        ];

        return TransportResult::success($messageId);
    }

    public function isAvailable(): bool
    {
        return $this->isAvailable;
    }

    public function getName(): string
    {
        return 'Mock Transport';
    }

    public function sendBatch(array $messages): array
    {
        $results = [];

        foreach ($messages as $index => $message) {
            if (! $message instanceof Message) {
                $results[$index] = TransportResult::failure('Invalid message at index ' . $index);

                continue;
            }

            $results[$index] = $this->send($message);
        }

        return $results;
    }

    // Test helper methods

    public function setShouldFail(bool $shouldFail, ?string $failureMessage = null): void
    {
        $this->shouldFail = $shouldFail;
        $this->failureMessage = $failureMessage;
    }

    public function setIsAvailable(bool $isAvailable): void
    {
        $this->isAvailable = $isAvailable;
    }

    public function getSentMessages(): array
    {
        return $this->sentMessages;
    }

    public function getLastSentMessage(): ?array
    {
        return end($this->sentMessages) ?: null;
    }

    public function getSentMessageCount(): int
    {
        return count($this->sentMessages);
    }

    public function clearSentMessages(): void
    {
        $this->sentMessages = [];
    }

    public function wasSentTo(string $email): bool
    {
        foreach ($this->sentMessages as $sentMessage) {
            /** @var Message $message */
            $message = $sentMessage['message'];

            foreach ($message->to as $recipient) {
                if ($recipient->value === $email) {
                    return true;
                }
            }
        }

        return false;
    }

    public function getSentMessagesTo(string $email): array
    {
        $messages = [];

        foreach ($this->sentMessages as $sentMessage) {
            /** @var Message $message */
            $message = $sentMessage['message'];

            foreach ($message->to as $recipient) {
                if ($recipient->value === $email) {
                    $messages[] = $sentMessage;

                    break;
                }
            }
        }

        return $messages;
    }

    public function getSentMessageWithSubject(string $subject): ?array
    {
        foreach ($this->sentMessages as $sentMessage) {
            /** @var Message $message */
            $message = $sentMessage['message'];

            if ($message->subject === $subject) {
                return $sentMessage;
            }
        }

        return null;
    }
}
