<?php

namespace MintyPHP\Service\Mail;

use MintyPHP\Domain\Taxonomy\MailLogStatus;
use MintyPHP\I18n;
use MintyPHP\Repository\Mail\MailLogRepositoryInterface;
use MintyPHP\Service\Settings\SettingsSmtpGateway;
use PHPMailer\PHPMailer\Exception as MailerException;
use PHPMailer\PHPMailer\PHPMailer;

class MailService
{
    public function __construct(
        private readonly MailLogRepositoryInterface $mailLogRepository,
        private readonly SettingsSmtpGateway $settingsSmtpGateway
    ) {
    }

    public function sendTemplate(
        string $template,
        array $vars,
        string $to,
        string $subject,
        ?string $locale = null
    ): array {
        $locale = $locale ?: (I18n::$locale ?? I18n::$defaultLocale);
        [$html, $text] = $this->renderTemplate($template, $vars, $locale);

        return $this->send($to, $subject, $html, $text, [
            'template' => $template,
        ]);
    }

    public function send(
        string $to,
        string $subject,
        string $html,
        string $text,
        array $meta = []
    ): array {
        // Log before sending so there's a record even if the send throws an exception.
        $logId = $this->mailLogRepository->create([
            'to_email' => $to,
            'subject' => $subject,
            'template' => $meta['template'] ?? null,
            'status' => MailLogStatus::Queued->value,
        ]);

        if (!class_exists(PHPMailer::class)) {
            if ($logId) {
                $this->mailLogRepository->markFailed($logId, 'PHPMailer is not installed');
            }
            return ['ok' => false, 'error' => 'mailer_missing'];
        }

        try {
            $mailer = $this->createMailer();
            $mailer->addAddress($to);
            $mailer->Subject = $subject;
            $mailer->Body = $html;
            $mailer->AltBody = $text;
            $mailer->isHTML(true);
            $mailer->send();

            if ($logId) {
                $this->mailLogRepository->markSent($logId, $mailer->getLastMessageID() ?: null);
            }
            return ['ok' => true];
        } catch (MailerException $e) {
            if ($logId) {
                $this->mailLogRepository->markFailed($logId, $e->getMessage());
            }
            return ['ok' => false, 'error' => 'send_failed'];
        }
    }

    private function renderTemplate(string $template, array $vars, string $locale): array
    {
        $base = dirname(__DIR__, 3) . '/templates/emails';
        $htmlPath = $base . '/' . $locale . '/' . $template . '.html';
        $textPath = $base . '/' . $locale . '/' . $template . '.txt';
        $htmlHeaderPath = $base . '/' . $locale . '/partials/header.html';
        $htmlFooterPath = $base . '/' . $locale . '/partials/footer.html';
        $textHeaderPath = $base . '/' . $locale . '/partials/header.txt';
        $textFooterPath = $base . '/' . $locale . '/partials/footer.txt';

        if (!is_file($htmlPath)) {
            $htmlPath = $base . '/' . $template . '.html';
        }
        if (!is_file($textPath)) {
            $textPath = $base . '/' . $template . '.txt';
        }
        $html = is_file($htmlPath) ? file_get_contents($htmlPath) : '';
        $text = is_file($textPath) ? file_get_contents($textPath) : '';
        if (!isset($vars['email_header'])) {
            $vars['email_header'] = is_file($htmlHeaderPath) ? file_get_contents($htmlHeaderPath) : '';
        }
        if (!isset($vars['email_footer'])) {
            $vars['email_footer'] = is_file($htmlFooterPath) ? file_get_contents($htmlFooterPath) : '';
        }
        if (!isset($vars['email_header_text'])) {
            $vars['email_header_text'] = is_file($textHeaderPath) ? file_get_contents($textHeaderPath) : '';
        }
        if (!isset($vars['email_footer_text'])) {
            $vars['email_footer_text'] = is_file($textFooterPath) ? file_get_contents($textFooterPath) : '';
        }

        foreach ($vars as $key => $value) {
            $placeholder = '{{' . $key . '}}';
            $html = str_replace($placeholder, (string) $value, $html);
            $text = str_replace($placeholder, (string) $value, $text);
        }
        // Second pass to resolve placeholders inside injected header/footer content.
        foreach ($vars as $key => $value) {
            $placeholder = '{{' . $key . '}}';
            $html = str_replace($placeholder, (string) $value, $html);
            $text = str_replace($placeholder, (string) $value, $text);
        }

        return [$html, $text];
    }

    private function createMailer(): PHPMailer
    {
        $mailer = new PHPMailer(true);
        $mailer->isSMTP();

        // DB setting takes priority; env var fallback allows Docker-compose-style configuration without a DB record.
        $host = $this->settingsSmtpGateway->getSmtpHost() ?? (getenv('SMTP_HOST') ?: '');
        $port = $this->settingsSmtpGateway->getSmtpPort() ?? (int) (getenv('SMTP_PORT') ?: 587);
        $user = $this->settingsSmtpGateway->getSmtpUser() ?? (getenv('SMTP_USER') ?: '');
        $pass = $this->settingsSmtpGateway->getSmtpPassword() ?? (getenv('SMTP_PASS') ?: '');
        $secure = $this->settingsSmtpGateway->getSmtpSecure() ?? strtolower((string) (getenv('SMTP_SECURE') ?: 'tls'));
        $from = $this->settingsSmtpGateway->getSmtpFrom() ?? (getenv('SMTP_FROM') ?: ($user ?: 'no-reply@localhost'));
        $fromName = $this->settingsSmtpGateway->getSmtpFromName() ?? (getenv('SMTP_FROM_NAME') ?: appTitle());

        $mailer->Host = $host;
        $mailer->Port = $port;
        // Enable SMTP auth only if credentials are configured — supports relay servers without auth.
        $mailer->SMTPAuth = $user !== '' || $pass !== '';
        $mailer->Username = $user;
        $mailer->Password = $pass;
        if (in_array($secure, ['tls', 'ssl'], true)) {
            $mailer->SMTPSecure = $secure;
        }
        $mailer->setFrom($from, $fromName);
        $mailer->CharSet = 'UTF-8';

        return $mailer;
    }
}
