<?php

declare(strict_types=1);

namespace App\Services;

final class DocumentMailService extends BaseService
{
    private const SUPPORTED_TYPES = [
        'DEVIS',
        'FACTURE',
        'BL',
        'BON_DE_LIVRAISON',
        'AVOIR',
    ];

    public function __construct(
        private readonly MailService $mail = new MailService(),
        private readonly DocumentEngine $documentEngine = new DocumentEngine(),
        private readonly SmtpConfigurationService $smtpConfiguration =
            new SmtpConfigurationService(),
        private readonly MailTemplateService $templates =
            new MailTemplateService()
    ) {
    }

    /**
     * Envoie un document PDF généré en mémoire.
     *
     * @param array<string,mixed> $document
     * @param array<int,array<string,mixed>> $lines
     * @return array<string,mixed>
     */
    public function sendDocument(
        string $type,
        array $document,
        array $lines,
        string $recipient,
        string $subject,
        string $message,
        bool $copySender = false
    ): array {
        $normalizedType = $this->normalizeType($type);
        $recipient = trim($recipient);
        $subject = trim($subject);
        $message = trim($message);

        if ($recipient === '' || filter_var($recipient, FILTER_VALIDATE_EMAIL) === false) {
            throw new \InvalidArgumentException(
                'L’adresse e-mail du destinataire n’est pas valide.'
            );
        }

        if ($subject === '') {
            throw new \InvalidArgumentException('L’objet de l’e-mail est obligatoire.');
        }

        if ($message === '') {
            throw new \InvalidArgumentException('Le message de l’e-mail est obligatoire.');
        }

        $pdf = $this->generatePdf($normalizedType, $document, $lines);
        $number = trim((string)($document['numero'] ?? 'document'));
        $filename = $this->documentFilename($normalizedType, $number);

        $bcc = [];

        if ($copySender) {
            $settings = $this->smtpConfiguration->getRuntimeConfiguration();
            $senderEmail = trim((string)($settings['smtp_from_email'] ?? ''));

            if ($senderEmail !== '') {
                $bcc[] = $senderEmail;
            }
        }

        $this->mail->send(
            recipient: $recipient,
            subject: $subject,
            htmlBody: $this->formatHtmlMessage($message),
            textBody: $message,
            attachments: [[
                'name' => $filename,
                'content' => $pdf,
                'mime' => 'application/pdf',
            ]],
            bcc: $bcc
        );

        return [
            'type' => $normalizedType,
            'number' => $number,
            'recipient' => $recipient,
            'subject' => $subject,
            'attachment_name' => $filename,
            'attachment_size' => strlen($pdf),
            'sent_at' => date('Y-m-d H:i:s'),
        ];
    }

    /**
     * Prépare les valeurs par défaut d’un formulaire d’envoi.
     *
     * @param array<string,mixed> $document
     * @return array<string,string>
     */
    public function defaults(string $type, array $document): array
    {
        $normalizedType = $this->normalizeType($type);
        $rendered = $this->templates->render($normalizedType, $document);
        $recipient = trim((string)(
            $document['client_email']
            ?? $document['email']
            ?? ''
        ));

        return [
            'recipient' => $recipient,
            'subject' => $rendered['subject'],
            'message' => $rendered['message'],
            'template_name' => $rendered['name'],
            'attachment_name' => $this->documentFilename(
                $normalizedType,
                trim((string)($document['numero'] ?? 'document'))
            ),
        ];
    }

    /**
     * @param array<string,mixed> $document
     * @param array<int,array<string,mixed>> $lines
     */
    private function generatePdf(string $type, array $document, array $lines): string
    {
        return match ($type) {
            'DEVIS' => $this->documentEngine->generateDevisPdf($document, $lines),
            'FACTURE' => $this->documentEngine->generateFacturePdf($document, $lines),
            'BL', 'BON_DE_LIVRAISON' =>
                $this->documentEngine->generateBonLivraisonPdf($document, $lines),
            'AVOIR' => $this->documentEngine->generateAvoirPdf($document, $lines),
            default => throw new \RuntimeException(
                'Ce type de document ne peut pas être envoyé par e-mail.'
            ),
        };
    }

    private function normalizeType(string $type): string
    {
        $type = strtoupper(trim($type));
        $type = str_replace([' ', '-'], '_', $type);

        if (!in_array($type, self::SUPPORTED_TYPES, true)) {
            throw new \InvalidArgumentException(
                'Type de document non pris en charge par la messagerie.'
            );
        }

        return $type;
    }

    private function typeLabel(string $type): string
    {
        return match ($type) {
            'DEVIS' => 'Devis',
            'FACTURE' => 'Facture',
            'BL', 'BON_DE_LIVRAISON' => 'Bon de livraison',
            'AVOIR' => 'Avoir',
            default => 'Document',
        };
    }

    private function articleForType(string $type): string
    {
        return match ($type) {
            'DEVIS' => 'notre devis',
            'FACTURE' => 'notre facture',
            'BL', 'BON_DE_LIVRAISON' => 'notre bon de livraison',
            'AVOIR' => 'notre avoir',
            default => 'notre document',
        };
    }

    private function documentFilename(string $type, string $number): string
    {
        $prefix = match ($type) {
            'DEVIS' => 'Devis',
            'FACTURE' => 'Facture',
            'BL', 'BON_DE_LIVRAISON' => 'Bon_livraison',
            'AVOIR' => 'Avoir',
            default => 'Document',
        };

        $number = preg_replace('/[^A-Za-z0-9_-]+/', '_', $number) ?: 'document';

        return $prefix . '_' . trim($number, '_') . '.pdf';
    }

    private function formatHtmlMessage(string $message): string
    {
        return '<div style="font-family:Arial,sans-serif;font-size:14px;line-height:1.6;color:#1f2937">'
            . nl2br(htmlspecialchars($message, ENT_QUOTES, 'UTF-8'))
            . '</div>';
    }
}
