<?php

declare(strict_types=1);

namespace App\Framework\Mail\Exceptions;

use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;

final class SmtpException extends FrameworkException
{
    public static function connectionFailed(string $host, int $port, string $error): self
    {
        return new self(
            message: "Failed to connect to SMTP server {$host}:{$port}: {$error}",
            context: ExceptionContext::forOperation('smtp_connect', 'mail')
                ->withData([
                    'host' => $host,
                    'port' => $port,
                    'error' => $error,
                ])
        );
    }

    public static function authenticationFailed(string $response): self
    {
        return new self(
            message: "SMTP authentication failed",
            context: ExceptionContext::forOperation('smtp_auth', 'mail')
                ->withData([
                    'smtp_response' => $response,
                ])
        );
    }

    public static function commandFailed(string $command, string $response): self
    {
        return new self(
            message: "SMTP command failed: {$command}",
            context: ExceptionContext::forOperation('smtp_command', 'mail')
                ->withData([
                    'command' => $command,
                    'smtp_response' => $response,
                ])
        );
    }

    public static function tlsFailed(): self
    {
        return new self(
            message: "Failed to enable TLS encryption",
            context: ExceptionContext::forOperation('smtp_tls', 'mail')
        );
    }

    public static function messageBuildFailed(string $reason): self
    {
        return new self(
            message: "Failed to build email message: {$reason}",
            context: ExceptionContext::forOperation('message_build', 'mail')
                ->withData([
                    'reason' => $reason,
                ])
        );
    }

    public static function messageValidationFailed(array $errors): self
    {
        return new self(
            message: "Message validation failed: " . implode(', ', $errors),
            context: ExceptionContext::forOperation('message_validation', 'mail')
                ->withData([
                    'validation_errors' => $errors,
                ])
        );
    }

    public static function mailFromFailed(string $sender, string $response): self
    {
        return new self(
            message: "MAIL FROM command failed for sender: {$sender}",
            context: ExceptionContext::forOperation('smtp_mail_from', 'mail')
                ->withData([
                    'sender' => $sender,
                    'smtp_response' => $response,
                ])
        );
    }

    public static function recipientFailed(string $recipient, string $response): self
    {
        return new self(
            message: "RCPT TO command failed for recipient: {$recipient}",
            context: ExceptionContext::forOperation('smtp_rcpt_to', 'mail')
                ->withData([
                    'recipient' => $recipient,
                    'smtp_response' => $response,
                ])
        );
    }

    public static function dataCommandFailed(string $response): self
    {
        return new self(
            message: "DATA command failed",
            context: ExceptionContext::forOperation('smtp_data', 'mail')
                ->withData([
                    'smtp_response' => $response,
                ])
        );
    }

    public static function messageSendFailed(string $response): self
    {
        return new self(
            message: "Message sending failed",
            context: ExceptionContext::forOperation('smtp_message_send', 'mail')
                ->withData([
                    'smtp_response' => $response,
                ])
        );
    }

    public static function socketError(string $host, int $port, string $operation): self
    {
        return new self(
            message: "Socket error during {$operation}",
            context: ExceptionContext::forOperation('smtp_socket', 'mail')
                ->withData([
                    'host' => $host,
                    'port' => $port,
                    'operation' => $operation,
                ])
        );
    }
}
