<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Whether Algo Forms built-in SMTP is enabled and has a host.
 *
 * @param array<string,mixed>|null $opts
 * @return bool
 */
function algo_forms_smtp_is_ready($opts = null)
{
    if ($opts === null) {
        $opts = algo_forms_get_options();
    }
    if (empty($opts['smtp_enabled'])) {
        return false;
    }
    $host = trim((string) ($opts['smtp_host'] ?? ''));
    return $host !== '';
}

/**
 * Effective SMTP password: wp-config constants win over DB.
 *
 * Supports ALGO_FORMS_SMTP_PASS, or WPMS_SMTP_PASS when WPMS constants are on.
 *
 * @param array<string,mixed> $opts
 * @return string
 */
function algo_forms_smtp_resolve_password(array $opts)
{
    if (defined('ALGO_FORMS_SMTP_PASS') && ALGO_FORMS_SMTP_PASS !== '') {
        return (string) ALGO_FORMS_SMTP_PASS;
    }
    if (defined('WPMS_ON') && WPMS_ON && defined('WPMS_SMTP_PASS') && WPMS_SMTP_PASS !== '') {
        return (string) WPMS_SMTP_PASS;
    }
    return (string) ($opts['smtp_pass'] ?? '');
}

/**
 * Decrypt a WP Mail SMTP stored password (sodium secretbox + base64).
 *
 * @param string $encrypted
 * @return string Plain password, or empty string on failure.
 */
function algo_forms_decrypt_wpms_password($encrypted)
{
    $encrypted = (string) $encrypted;
    if ($encrypted === '') {
        return '';
    }

    // Prefer the official helper when the plugin is loaded.
    if (class_exists('WPMailSMTP\\Helpers\\Crypto')) {
        try {
            $plain = \WPMailSMTP\Helpers\Crypto::decrypt($encrypted);
            if (is_string($plain) && $plain !== '' && $plain !== $encrypted) {
                return $plain;
            }
            // Crypto::decrypt returns the original ciphertext on failure — treat as fail.
            if (is_string($plain) && $plain !== $encrypted) {
                return $plain;
            }
        } catch (\Exception $e) {
            // Fall through to local decrypt.
        }
    }

    if (!function_exists('sodium_crypto_secretbox_open')) {
        return '';
    }

    $key = '';
    if (defined('WPMS_CRYPTO_KEY') && WPMS_CRYPTO_KEY !== '') {
        $key = (string) WPMS_CRYPTO_KEY;
        // Key may be stored base64-encoded like the option.
        $decoded_key = base64_decode($key, true);
        if ($decoded_key !== false && strlen($decoded_key) === SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
            $key = $decoded_key;
        }
    } else {
        $stored = get_option('wp_mail_smtp_mail_key');
        if (!is_string($stored) || $stored === '') {
            return '';
        }
        $key = base64_decode($stored, true);
        if ($key === false) {
            return '';
        }
    }

    $decoded = base64_decode($encrypted, true);
    if ($decoded === false) {
        return '';
    }

    if (strlen($decoded) < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
        return '';
    }

    $nonce = substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $ciphertext = substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $message = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
    if ($message === false) {
        return '';
    }

    return (string) $message;
}

/**
 * Read SMTP settings currently used by WP Mail SMTP (constants + DB).
 *
 * @return array<string,mixed>|null Normalized Algo Forms SMTP fields, or null.
 */
function algo_forms_read_wp_mail_smtp_settings()
{
    $host = '';
    $port = 587;
    $encryption = 'tls';
    $auth = 1;
    $user = '';
    $pass = '';
    $from_email = '';
    $from_name = '';
    $mailer = '';

    // 1) Official Options API (handles decrypt + WPMS_* constants).
    if (class_exists('WPMailSMTP\\Options')) {
        try {
            $options = \WPMailSMTP\Options::init();
            $mailer = (string) $options->get('mail', 'mailer');
            $host = (string) $options->get('smtp', 'host');
            $port = (int) $options->get('smtp', 'port');
            $enc = (string) $options->get('smtp', 'encryption');
            $encryption = ($enc === '' || $enc === 'none') ? 'none' : $enc;
            $auth = $options->get('smtp', 'auth') ? 1 : 0;
            $user = (string) $options->get('smtp', 'user');
            $pass = (string) $options->get('smtp', 'pass');
            $from_email = (string) $options->get('mail', 'from_email');
            $from_name = (string) $options->get('mail', 'from_name');
        } catch (\Exception $e) {
            // Fall through.
        }
    }

    // 2) wp-config constants (even if WP Mail SMTP is deactivated).
    if (defined('WPMS_ON') && WPMS_ON) {
        if (defined('WPMS_MAILER') && WPMS_MAILER !== '') {
            $mailer = (string) WPMS_MAILER;
        }
        if (defined('WPMS_SMTP_HOST') && WPMS_SMTP_HOST !== '') {
            $host = (string) WPMS_SMTP_HOST;
        }
        if (defined('WPMS_SMTP_PORT') && WPMS_SMTP_PORT) {
            $port = (int) WPMS_SMTP_PORT;
        }
        if (defined('WPMS_SSL')) {
            $encryption = WPMS_SSL === '' ? 'none' : (string) WPMS_SSL;
        }
        if (defined('WPMS_SMTP_AUTH')) {
            $auth = WPMS_SMTP_AUTH ? 1 : 0;
        }
        if (defined('WPMS_SMTP_USER') && WPMS_SMTP_USER !== '') {
            $user = (string) WPMS_SMTP_USER;
        }
        if (defined('WPMS_SMTP_PASS') && WPMS_SMTP_PASS !== '') {
            $pass = (string) WPMS_SMTP_PASS;
        }
        if (defined('WPMS_MAIL_FROM') && WPMS_MAIL_FROM !== '') {
            $from_email = (string) WPMS_MAIL_FROM;
        }
        if (defined('WPMS_MAIL_FROM_NAME') && WPMS_MAIL_FROM_NAME !== '') {
            $from_name = (string) WPMS_MAIL_FROM_NAME;
        }
    }

    // 3) Raw option + decrypt (plugin inactive, no constants).
    if ($host === '') {
        $raw = get_option('wp_mail_smtp');
        if (is_array($raw)) {
            $mailer = $mailer !== '' ? $mailer : (string) ($raw['mail']['mailer'] ?? '');
            $smtp = isset($raw['smtp']) && is_array($raw['smtp']) ? $raw['smtp'] : array();
            $host = (string) ($smtp['host'] ?? '');
            $port = (int) ($smtp['port'] ?? 587);
            $enc = (string) ($smtp['encryption'] ?? 'tls');
            $encryption = ($enc === '' || $enc === 'none') ? 'none' : $enc;
            $auth = !empty($smtp['auth']) ? 1 : 0;
            $user = (string) ($smtp['user'] ?? '');
            if ($pass === '' && !empty($smtp['pass'])) {
                $pass = algo_forms_decrypt_wpms_password((string) $smtp['pass']);
                // Older installs may have stored plain text.
                if ($pass === '' && (string) $smtp['pass'] !== '') {
                    $candidate = (string) $smtp['pass'];
                    // Only accept as plain if it does not look like base64 ciphertext.
                    if (strlen($candidate) < 40) {
                        $pass = $candidate;
                    }
                }
            }
            $from_email = $from_email !== '' ? $from_email : (string) ($raw['mail']['from_email'] ?? '');
            $from_name = $from_name !== '' ? $from_name : (string) ($raw['mail']['from_name'] ?? '');
        }
    }

    if ($host === '') {
        return null;
    }

    // Only import when WP Mail SMTP is (or was) using the SMTP mailer.
    if ($mailer !== '' && $mailer !== 'smtp' && $mailer !== 'pepipost') {
        return null;
    }

    if ($port < 1 || $port > 65535) {
        $port = 587;
    }
    if (!in_array($encryption, array('none', 'ssl', 'tls'), true)) {
        $encryption = 'tls';
    }

    return array(
        'smtp_enabled' => 1,
        'smtp_host' => $host,
        'smtp_port' => $port,
        'smtp_encryption' => $encryption,
        'smtp_auth' => $auth,
        'smtp_user' => $user,
        'smtp_pass' => $pass,
        'from_email' => $from_email && is_email($from_email) ? $from_email : '',
        'from_name' => $from_name,
        'source' => 'wp_mail_smtp',
    );
}

/**
 * Copy WP Mail SMTP settings into Algo Forms options (once, or forced).
 *
 * @param bool $force Re-import even if Algo Forms already has a host.
 * @return array{ok:bool,message:string,imported:bool}
 */
function algo_forms_import_wp_mail_smtp_settings($force = false)
{
    $opts = algo_forms_get_options();
    $has_host = trim((string) ($opts['smtp_host'] ?? '')) !== '';

    if (!$force && $has_host) {
        return array(
            'ok' => true,
            'imported' => false,
            'message' => __('Algo Forms SMTP is already configured.', 'algo-forms'),
        );
    }

    $wpms = algo_forms_read_wp_mail_smtp_settings();
    if (!$wpms) {
        return array(
            'ok' => false,
            'imported' => false,
            'message' => __('No WP Mail SMTP SMTP settings found to import.', 'algo-forms'),
        );
    }

    $opts['smtp_enabled'] = 1;
    $opts['smtp_host'] = $wpms['smtp_host'];
    $opts['smtp_port'] = $wpms['smtp_port'];
    $opts['smtp_encryption'] = $wpms['smtp_encryption'];
    $opts['smtp_auth'] = $wpms['smtp_auth'];
    $opts['smtp_user'] = $wpms['smtp_user'];

    // Keep existing password if WPMS pass could not be decrypted and we already have one.
    if ($wpms['smtp_pass'] !== '') {
        $opts['smtp_pass'] = $wpms['smtp_pass'];
    } elseif (!$has_host) {
        $opts['smtp_pass'] = '';
    }

    if ($wpms['from_email'] !== '' && empty($opts['from_email'])) {
        $opts['from_email'] = $wpms['from_email'];
    }
    if ($wpms['from_name'] !== '' && empty($opts['from_name'])) {
        $opts['from_name'] = $wpms['from_name'];
    }

    update_option(ALGO_FORMS_OPTIONS_KEY, $opts, false);
    update_option('algo_forms_smtp_wpms_imported', 1, false);

    $pass_ok = algo_forms_smtp_resolve_password($opts) !== '';
    $message = $pass_ok
        ? __('Imported SMTP settings from WP Mail SMTP. You can deactivate WP Mail SMTP after a successful test email.', 'algo-forms')
        : __('Imported SMTP host/user from WP Mail SMTP, but the password could not be read. Paste the password once below (or define ALGO_FORMS_SMTP_PASS / WPMS_SMTP_PASS in wp-config.php).', 'algo-forms');

    return array(
        'ok' => $pass_ok || $wpms['smtp_host'] !== '',
        'imported' => true,
        'message' => $message,
    );
}

/**
 * One-time auto-import after plugin update / first load.
 *
 * @return void
 */
function algo_forms_maybe_auto_import_wp_mail_smtp()
{
    if (get_option('algo_forms_smtp_wpms_imported')) {
        return;
    }
    if (!current_user_can(ALGO_FORMS_CAP)) {
        return;
    }

    $opts = algo_forms_get_options();
    if (trim((string) ($opts['smtp_host'] ?? '')) !== '') {
        update_option('algo_forms_smtp_wpms_imported', 1, false);
        return;
    }

    algo_forms_import_wp_mail_smtp_settings(false);
}
add_action('admin_init', 'algo_forms_maybe_auto_import_wp_mail_smtp', 5);

/**
 * Sanitize SMTP settings from POST into the options array.
 * Empty password field keeps the previously saved password.
 *
 * @param array<string,mixed> $opts
 * @return array<string,mixed>
 */
function algo_forms_sanitize_smtp_options_from_post(array $opts)
{
    $opts['smtp_enabled'] = !empty($_POST['algo_forms_smtp_enabled']) ? 1 : 0;
    $opts['smtp_host'] = sanitize_text_field(wp_unslash($_POST['algo_forms_smtp_host'] ?? ''));
    $opts['smtp_port'] = absint($_POST['algo_forms_smtp_port'] ?? 587);
    if ($opts['smtp_port'] < 1 || $opts['smtp_port'] > 65535) {
        $opts['smtp_port'] = 587;
    }

    $encryption = sanitize_key(wp_unslash($_POST['algo_forms_smtp_encryption'] ?? 'tls'));
    if (!in_array($encryption, array('none', 'ssl', 'tls'), true)) {
        $encryption = 'tls';
    }
    $opts['smtp_encryption'] = $encryption;

    $opts['smtp_user'] = sanitize_text_field(wp_unslash($_POST['algo_forms_smtp_user'] ?? ''));

    $pass_raw = isset($_POST['algo_forms_smtp_pass']) ? (string) wp_unslash($_POST['algo_forms_smtp_pass']) : '';
    // Placeholder / blank means keep existing password.
    if ($pass_raw !== '' && $pass_raw !== '********') {
        $opts['smtp_pass'] = $pass_raw;
    }

    $opts['smtp_auth'] = !empty($_POST['algo_forms_smtp_auth']) ? 1 : 0;

    return $opts;
}

/**
 * Configure PHPMailer to use Algo Forms SMTP when enabled.
 *
 * @param PHPMailer\PHPMailer\PHPMailer $phpmailer
 * @return void
 */
function algo_forms_phpmailer_init($phpmailer)
{
    $opts = algo_forms_get_options();
    if (!algo_forms_smtp_is_ready($opts)) {
        return;
    }

    $host = trim((string) $opts['smtp_host']);
    $port = (int) ($opts['smtp_port'] ?: 587);
    $user = (string) ($opts['smtp_user'] ?? '');
    if (defined('ALGO_FORMS_SMTP_USER') && ALGO_FORMS_SMTP_USER !== '') {
        $user = (string) ALGO_FORMS_SMTP_USER;
    } elseif (defined('WPMS_ON') && WPMS_ON && defined('WPMS_SMTP_USER') && WPMS_SMTP_USER !== '') {
        $user = (string) WPMS_SMTP_USER;
    }
    $pass = algo_forms_smtp_resolve_password($opts);
    $encryption = (string) ($opts['smtp_encryption'] ?? 'tls');
    $auth = !array_key_exists('smtp_auth', $opts) ? ($user !== '') : !empty($opts['smtp_auth']);

    $phpmailer->isSMTP();
    $phpmailer->Host = $host;
    $phpmailer->Port = $port;
    $phpmailer->SMTPAuth = (bool) $auth;

    if ($auth) {
        $phpmailer->Username = $user;
        $phpmailer->Password = $pass;
    }

    // PHPMailer: 'ssl' = SMTPS, 'tls' = STARTTLS.
    if ($encryption === 'ssl') {
        $phpmailer->SMTPSecure = 'ssl';
        $phpmailer->SMTPAutoTLS = true;
    } elseif ($encryption === 'tls') {
        $phpmailer->SMTPSecure = 'tls';
        $phpmailer->SMTPAutoTLS = true;
    } else {
        $phpmailer->SMTPSecure = '';
        $phpmailer->SMTPAutoTLS = false;
    }

    $from_email = trim((string) ($opts['from_email'] ?? ''));
    $from_name = trim((string) ($opts['from_name'] ?? ''));
    if ($from_email === '' || !is_email($from_email)) {
        if ($user !== '' && is_email($user)) {
            $from_email = $user;
        }
    }
    if ($from_email !== '' && is_email($from_email)) {
        try {
            $phpmailer->setFrom($from_email, $from_name !== '' ? $from_name : '', false);
        } catch (\Exception $e) {
            // Keep PHPMailer's existing From if setFrom rejects the address.
        }
    }

    // Reply-To via PHPMailer only. Yahoo SMTP rejects a Reply-To that is not the Yahoo account
    // ("Data not accepted"). Skip it for Yahoo so mail still sends.
    $reply_to = sanitize_email((string) ($opts['reply_to_email'] ?? ''));
    $yahoo    = (false !== stripos($host, 'yahoo.'));
    if ($reply_to !== '' && is_email($reply_to) && !$yahoo && strcasecmp($reply_to, $from_email) !== 0) {
        try {
            if (method_exists($phpmailer, 'clearReplyTos')) {
                $phpmailer->clearReplyTos();
            }
            $phpmailer->addReplyTo($reply_to, $from_name !== '' ? $from_name : '');
        } catch (\Exception $e) {
            // Leave default Reply-To (From) if the provider rejects it.
        }
    }

    $phpmailer->Timeout = 20;
}
add_action('phpmailer_init', 'algo_forms_phpmailer_init', 20);

/**
 * Human-readable mail transport status for the admin UI.
 *
 * @return array{ready:bool,label:string,detail:string,conflict:bool}
 */
function algo_forms_mail_transport_status()
{
    $opts = algo_forms_get_options();
    $external = algo_forms_external_smtp_plugin_active();
    $ready = algo_forms_smtp_is_ready($opts);

    if ($ready) {
        $host = (string) $opts['smtp_host'];
        $port = (int) ($opts['smtp_port'] ?: 587);
        $enc = (string) ($opts['smtp_encryption'] ?? 'tls');
        $detail = sprintf(
            /* translators: 1: host, 2: port, 3: encryption */
            __('Sending via SMTP %1$s:%2$d (%3$s). No other mail plugin required.', 'algo-forms'),
            $host,
            $port,
            $enc === 'none' ? __('no encryption', 'algo-forms') : strtoupper($enc)
        );
        return array(
            'ready' => true,
            'label' => __('Algo Forms SMTP active', 'algo-forms'),
            'detail' => $detail,
            'conflict' => $external,
        );
    }

    if ($external) {
        return array(
            'ready' => true,
            'label' => __('External SMTP plugin detected', 'algo-forms'),
            'detail' => __('Algo Forms SMTP is off. Mail is being handled by another plugin. Enable Algo Forms SMTP below to become fully self-contained.', 'algo-forms'),
            'conflict' => false,
        );
    }

    return array(
        'ready' => false,
        'label' => __('Using WordPress default mail', 'algo-forms'),
        'detail' => __('This often fails or lands in spam on shared hosting. Enable SMTP below with your mailbox credentials for reliable delivery.', 'algo-forms'),
        'conflict' => false,
    );
}

/**
 * Whether a third-party SMTP plugin is active (informational only).
 *
 * @return bool
 */
function algo_forms_external_smtp_plugin_active()
{
    if (defined('WPMS_PLUGIN_VER') || defined('WP_MAIL_SMTP_VERSION')) {
        return true;
    }
    if (function_exists('wp_mail_smtp') || class_exists('WPMailSMTP\\Core') || class_exists('EasyWPSMTP\\Core')) {
        return true;
    }
    if (!function_exists('is_plugin_active')) {
        require_once ABSPATH . 'wp-admin/includes/plugin.php';
    }
    $smtp_plugins = array(
        'wp-mail-smtp/wp_mail_smtp.php',
        'wp-mail-smtp-pro/wp_mail_smtp.php',
        'easy-wp-smtp/easy-wp-smtp.php',
        'fluent-smtp/fluent-smtp.php',
        'post-smtp/postman-smtp.php',
    );
    foreach ($smtp_plugins as $plugin) {
        if (is_plugin_active($plugin)) {
            return true;
        }
        if (function_exists('is_plugin_active_for_network') && is_plugin_active_for_network($plugin)) {
            return true;
        }
    }
    return false;
}
