<?php

declare(strict_types=1);

namespace App\Framework\Mail\Commands;

use App\Framework\CommandBus\CommandHandler;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Logging\Logger;
use App\Framework\Mail\Exceptions\SmtpException;
use App\Framework\Mail\TransportInterface;

final readonly class SendEmailCommandHandler
{
    public function __construct(
        private TransportInterface $transport,
        private Logger $logger,
    ) {
    }

    #[CommandHandler]
    public function handle(SendEmailCommand $command): void
    {
        try {
            $this->logger->info('Sending email via queue', [
                'to' => $command->message->to->toString(),
                'subject' => $command->message->subject,
                'transport' => $this->transport->getName(),
            ]);

            $result = $this->transport->send($command->message);

            if ($result->isFailure()) {
                $this->logger->error('Email sending failed', [
                    'error' => $result->getError(),
                    'metadata' => $result->getMetadata(),
                    'to' => $command->message->to->toString(),
                    'subject' => $command->message->subject,
                ]);

                throw new SmtpException(
                    message: 'Failed to send email: ' . $result->getError(),
                    context: ExceptionContext::forOperation('send_email_command', 'mail')
                        ->withData([
                            'transport_error' => $result->getError(),
                            'transport_metadata' => $result->getMetadata(),
                            'message_to' => $command->message->to->toString(),
                            'message_subject' => $command->message->subject,
                        ])
                );
            }

            $this->logger->info('Email sent successfully', [
                'message_id' => $result->getMessageId(),
                'to' => $command->message->to->toString(),
                'subject' => $command->message->subject,
                'transport' => $this->transport->getName(),
            ]);

        } catch (SmtpException $e) {
            $this->logger->error('SMTP exception during email sending', [
                'exception' => $e->toArray(),
                'to' => $command->message->to->toString(),
                'subject' => $command->message->subject,
            ]);

            // Re-throw to trigger queue retry logic
            throw $e;

        } catch (\Exception $e) {
            $this->logger->error('Unexpected exception during email sending', [
                'exception_class' => get_class($e),
                'exception_message' => $e->getMessage(),
                'to' => $command->message->to->toString(),
                'subject' => $command->message->subject,
            ]);

            // Wrap in SmtpException for consistent error handling
            throw new SmtpException(
                message: 'Unexpected error while sending email: ' . $e->getMessage(),
                previous: $e,
                context: ExceptionContext::forOperation('send_email_command', 'mail')
                    ->withData([
                        'original_exception' => get_class($e),
                        'original_message' => $e->getMessage(),
                        'message_to' => $command->message->to->toString(),
                        'message_subject' => $command->message->subject,
                    ])
            );
        }
    }
}
