<?php
declare(strict_types=1);

/**
 * /includes/mailer.php
 * - Відправка email через PHPMailer (SMTP)
 * - Налаштування з /includes/config_mail.php
 * - Debug в файл або в php error_log
 *
 * БЕЗПЕКА (посилено):
 * - валідація email отримувача
 * - захист від CRLF у subject
 * - debug-лог у web-root не використовується
 * - debug у вебі не вмикається, якщо явно не дозволено в config_mail.php
 *
 * Важливо для доставляння:
 * Якщо SMTP-логін Gmail, а from_email інший (admin@...), то ставимо From=$username (gmail),
 * а admin@... ставимо як Reply-To. Це зменшує шанс, що лист "зникне".
 */

require_once __DIR__ . '/helpers.php';

if (!function_exists('mailer_is_web_context')) {
    function mailer_is_web_context(): bool
    {
        return PHP_SAPI !== 'cli';
    }
}

if (!function_exists('mailer_is_path_under')) {
    function mailer_is_path_under(string $path, string $root): bool
    {
        $path = str_replace('\\', '/', $path);
        $root = rtrim(str_replace('\\', '/', $root), '/');
        return $root !== '' && strncmp($path, $root . '/', strlen($root) + 1) === 0;
    }
}

if (!function_exists('mailer_safe_debug_log_target')) {
    function mailer_safe_debug_log_target(string $debugLog): string
    {
        $debugLog = trim($debugLog);
        if ($debugLog === '' || $debugLog === 'php_error_log') {
            return 'php_error_log';
        }

        $docRoot = trim((string)($_SERVER['DOCUMENT_ROOT'] ?? ''));
        if ($docRoot !== '') {
            $docRootReal = realpath($docRoot);
            $targetDir = dirname($debugLog);
            $targetDirReal = realpath($targetDir);
            if ($docRootReal && $targetDirReal && mailer_is_path_under($targetDirReal, $docRootReal)) {
                return 'php_error_log';
            }
        }

        return $debugLog;
    }
}

if (!function_exists('mailer_can_enable_debug')) {
    function mailer_can_enable_debug(array $mc): bool
    {
        $allow = (bool)($mc['allow_debug_in_web'] ?? false);
        if (!mailer_is_web_context()) {
            return true;
        }
        return $allow;
    }
}

function mailer_send(string $toEmail, string $toName, string $subject, string $htmlBody, string $textBody = ''): array
{
    $cfgPath = __DIR__ . '/config_mail.php';
    if (!is_file($cfgPath)) {
        return ['ok' => false, 'error' => 'config_mail.php not found'];
    }

    $mc = require $cfgPath;
    if (!is_array($mc)) {
        return ['ok' => false, 'error' => 'config_mail.php invalid'];
    }

    $phpMailerBase = __DIR__ . '/PHPMailer/src';
    $f1 = $phpMailerBase . '/Exception.php';
    $f2 = $phpMailerBase . '/PHPMailer.php';
    $f3 = $phpMailerBase . '/SMTP.php';

    if (!is_file($f1) || !is_file($f2) || !is_file($f3)) {
        return ['ok' => false, 'error' => 'PHPMailer not found in /includes/PHPMailer/src'];
    }

    require_once $f1;
    require_once $f2;
    require_once $f3;

    $host = (string)($mc['host'] ?? '');
    $user = (string)($mc['username'] ?? '');
    $pass = (string)($mc['password'] ?? '');
    $port = (int)($mc['port'] ?? 587);
    $enc  = strtolower((string)($mc['encryption'] ?? 'tls'));

    $fromEmail = (string)($mc['from_email'] ?? '');
    $fromName  = (string)($mc['from_name'] ?? '');

    $debug    = (int)($mc['debug'] ?? 0);
    $debugLog = mailer_safe_debug_log_target((string)($mc['debug_log'] ?? ''));

    $toEmail = trim($toEmail);
    if ($toEmail === '' || !filter_var($toEmail, FILTER_VALIDATE_EMAIL)) {
        return ['ok' => false, 'error' => 'Invalid recipient email'];
    }
    $toName = trim($toName);

    $subject = preg_replace('/[\r\n]+/', ' ', $subject);
    $subject = trim((string)$subject);
    if ($subject === '') {
        $subject = 'Notification';
    }

    if ($host === '' || $user === '' || $pass === '') {
        return ['ok' => false, 'error' => 'SMTP config incomplete'];
    }
    if ($fromEmail === '') $fromEmail = $user;

    $writeDebug = function (string $line) use ($debugLog): void {
        $line = date('c') . ' ' . $line . "\n";

        if ($debugLog === 'php_error_log' || $debugLog === '') {
            error_log($line);
            return;
        }

        $dir = dirname($debugLog);
        if (!is_dir($dir)) {
            @mkdir($dir, 0775, true);
        }
        @file_put_contents($debugLog, $line, FILE_APPEND);
    };

    try {
        $mail = new \PHPMailer\PHPMailer\PHPMailer(true);
        $mail->CharSet = 'UTF-8';

        if ($debug > 0 && mailer_can_enable_debug($mc)) {
            $mail->SMTPDebug = $debug;
            $mail->Debugoutput = function ($str, $level) use ($writeDebug) {
                $writeDebug('[SMTP:' . (int)$level . '] ' . (string)$str);
            };
        }

        $mail->isSMTP();
        $mail->Host = $host;
        $mail->SMTPAuth = true;
        $mail->Username = $user;
        $mail->Password = $pass;
        $mail->Port = $port;

        if ($enc === 'ssl') {
            $mail->SMTPSecure = \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
        } else {
            $mail->SMTPSecure = \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
        }

        if (strcasecmp($fromEmail, $user) !== 0) {
            $mail->setFrom($user, ($fromName !== '' ? $fromName : $user));
            $mail->addReplyTo($fromEmail, ($fromName !== '' ? $fromName : $fromEmail));
        } else {
            $mail->setFrom($fromEmail, ($fromName !== '' ? $fromName : $fromEmail));
        }

        $mail->Sender = $user;
        $mail->addAddress($toEmail, ($toName !== '' ? $toName : $toEmail));

        $mail->isHTML(true);
        $mail->Subject = $subject;
        $mail->Body = $htmlBody;
        $mail->AltBody = ($textBody !== '' ? $textBody : strip_tags($htmlBody));

        $mail->send();

        $mid = '';
        if (property_exists($mail, 'MessageID')) {
            $mid = (string)$mail->MessageID;
        }

        return ['ok' => true, 'error' => '', 'message_id' => $mid];
    } catch (\Throwable $e) {
        if ($debug > 0 && mailer_can_enable_debug($mc)) {
            $writeDebug('[ERROR] ' . $e->getMessage());
        }
        return ['ok' => false, 'error' => $e->getMessage()];
    }
}
