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

/**
 * @return array<string, mixed>
 */
function algo_forms_default_options()
{
    return array(
        'send_notifications' => 1,
        'send_visitor_copy' => 1,
        'recipients' => array(),
        'subject_template' => 'New contact: {form_title} — {site_name}',
        'visitor_subject_template' => 'Thanks for contacting {site_name}',
        'visitor_intro' => 'Thank you for your message. We have received your request and will get back to you shortly.',
        'from_name' => '',
        'from_email' => '',
        'reply_to_email' => 'info@algorisys.com',
        'smtp_enabled' => 0,
        'smtp_host' => '',
        'smtp_port' => 587,
        'smtp_encryption' => 'tls',
        'smtp_auth' => 1,
        'smtp_user' => '',
        'smtp_pass' => '',
        // Pro
        'pro_active' => 0,
        'pro_license_key' => '',
        'spam_honeypot' => 1,
        'spam_min_seconds' => 2,
        'spam_rate_limit' => 8,
        'spam_rate_window' => HOUR_IN_SECONDS,
    );
}

/**
 * Create the default site contact form if missing.
 * Shortcode: [algo_form name="contact"]
 *
 * @return void
 */
function algo_forms_ensure_default_contact_form()
{
    global $wpdb;

    $table = $wpdb->prefix . 'algo_forms';
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table)));
    if ($exists !== $table) {
        return;
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $found = $wpdb->get_var($wpdb->prepare(
        "SELECT id FROM {$table} WHERE form_name = %s LIMIT 1",
        'contact'
    ));

    if ($found) {
        update_option('algo_forms_contact_seeded', 1, false);
        return;
    }

    $fields = algo_forms_normalize_fields(array(
        array('key' => 'name', 'label' => 'Full name', 'type' => 'text', 'required' => true),
        array('key' => 'email', 'label' => 'Work email', 'type' => 'email', 'required' => true),
        array('key' => 'phone', 'label' => 'Phone', 'type' => 'tel', 'required' => false),
        array('key' => 'company', 'label' => 'Company', 'type' => 'text', 'required' => false),
        array(
            'key' => 'interest',
            'label' => 'I am interested in',
            'type' => 'select',
            'required' => false,
            'options' => array(
                'IBM Planning Analytics',
                'IBM Cognos Analytics',
                'IBM Watson / AI',
                'Skillengine',
                'Propeak',
                'Low Code Application',
                'General enquiry',
            ),
        ),
        array('key' => 'message', 'label' => 'Message', 'type' => 'textarea', 'required' => true),
    ));

    $messages = array_merge(algo_forms_default_messages(), array(
        'submit_label' => __('Send message', 'algo-forms'),
        'sending_label' => __('Sending…', 'algo-forms'),
        'success_message' => __('Thank you. We have received your message and will get back to you shortly.', 'algo-forms'),
        'show_title' => '1',
    ));

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
    $wpdb->insert(
        $table,
        array(
            'form_name' => 'contact',
            'form_title' => 'Contact us',
            'fields' => wp_json_encode($fields),
            'messages' => wp_json_encode($messages),
            'notify_emails' => '',
            'email_subject' => 'New contact from {site_name}',
        ),
        array('%s', '%s', '%s', '%s', '%s', '%s')
    );

    update_option('algo_forms_contact_seeded', 1, false);
}

/**
 * Create the plugin marketplace request form if missing.
 * Shortcode: [algo_form name="plugin-request-form"]
 *
 * @return void
 */
function algo_forms_ensure_default_plugin_request_form()
{
    global $wpdb;

    $table = $wpdb->prefix . 'algo_forms';
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table)));
    if ($exists !== $table) {
        return;
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $found = $wpdb->get_var($wpdb->prepare(
        "SELECT id FROM {$table} WHERE form_name = %s LIMIT 1",
        'plugin-request-form'
    ));

    if ($found) {
        update_option('algo_forms_plugin_request_seeded', 1, false);
        return;
    }

    $fields = algo_forms_normalize_fields(array(
        array('key' => 'first-name', 'label' => 'Full Name', 'type' => 'text', 'required' => true),
        array('key' => 'email', 'label' => 'Email', 'type' => 'email', 'required' => true),
        array('key' => 'phone', 'label' => 'Phone', 'type' => 'tel', 'required' => true),
        array('key' => 'message', 'label' => 'Message', 'type' => 'textarea', 'required' => false),
    ));

    $messages = array_merge(algo_forms_default_messages(), array(
        'submit_label' => __('Send request', 'algo-forms'),
        'sending_label' => __('Sending…', 'algo-forms'),
        'success_message' => __('Thank you. We have received your plugin request and will get back to you shortly.', 'algo-forms'),
        'show_title' => '0',
    ));

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
    $wpdb->insert(
        $table,
        array(
            'form_name' => 'plugin-request-form',
            'form_title' => 'Plugin Request Form',
            'fields' => wp_json_encode($fields),
            'messages' => wp_json_encode($messages),
            'notify_emails' => '',
            'email_subject' => '{form_title} — {site_name}',
        ),
        array('%s', '%s', '%s', '%s', '%s', '%s')
    );

    update_option('algo_forms_plugin_request_seeded', 1, false);
}

/**
 * Enable "Show form title" for the default contact form if the setting is unset.
 *
 * @return void
 */
function algo_forms_maybe_enable_contact_show_title()
{
    if (get_option('algo_forms_contact_show_title_v1')) {
        return;
    }

    global $wpdb;
    $table = $wpdb->prefix . 'algo_forms';
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table)));
    if ($exists !== $table) {
        return;
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $form = $wpdb->get_row($wpdb->prepare(
        "SELECT id, messages FROM {$table} WHERE form_name = %s LIMIT 1",
        'contact'
    ));

    if ($form) {
        $messages = json_decode((string) $form->messages, true);
        if (!is_array($messages)) {
            $messages = array();
        }
        if (!array_key_exists('show_title', $messages)) {
            $messages['show_title'] = '1';
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                $table,
                array('messages' => wp_json_encode($messages)),
                array('id' => (int) $form->id),
                array('%s'),
                array('%d')
            );
        }
    }

    update_option('algo_forms_contact_show_title_v1', 1, false);
}

/**
 * @return array<string, mixed>
 */
function algo_forms_get_options()
{
    $opts = get_option(ALGO_FORMS_OPTIONS_KEY, array());
    if (!is_array($opts)) {
        $opts = array();
    }
    $merged = array_merge(algo_forms_default_options(), $opts);
    $merged['recipients'] = algo_forms_normalize_recipient_entries($merged['recipients'] ?? array());
    return $merged;
}

/**
 * @return array<string, string>
 */
function algo_forms_default_messages()
{
    return array(
        'submit_label' => __('Submit', 'algo-forms'),
        'sending_label' => __('Sending…', 'algo-forms'),
        'success_message' => __('Thank you. Your message has been sent.', 'algo-forms'),
        'error_generic' => __('Something went wrong. Please try again.', 'algo-forms'),
        'required_message' => __('%s is required.', 'algo-forms'),
        'invalid_email_message' => __('Please enter a valid email for %s.', 'algo-forms'),
    );
}

/**
 * Decode stored form messages JSON.
 *
 * @param object|null $form Form row.
 * @return array<string, mixed>
 */
function algo_forms_decode_form_messages($form)
{
    if (!$form || empty($form->messages)) {
        return array();
    }
    $decoded = json_decode((string) $form->messages, true);
    return is_array($decoded) ? $decoded : array();
}

/**
 * Whether the form title should render on the front end (admin setting).
 *
 * @param object $form Form row.
 * @return bool
 */
function algo_forms_form_shows_title($form)
{
    $stored = algo_forms_decode_form_messages($form);
    if (!array_key_exists('show_title', $stored)) {
        return false;
    }
    $value = $stored['show_title'];
    return !empty($value) && $value !== '0' && $value !== 'false';
}

/**
 * @param object $form
 * @return array<string, string>
 */
function algo_forms_get_form_messages($form)
{
    $defaults = algo_forms_default_messages();
    $stored = algo_forms_decode_form_messages($form);
    $out = $defaults;
    foreach ($defaults as $key => $fallback) {
        if (isset($stored[$key]) && is_string($stored[$key]) && trim($stored[$key]) !== '') {
            $out[$key] = $stored[$key];
        }
    }
    return $out;
}

/**
 * @param array<string, mixed> $field
 * @param int                  $index
 * @return string
 */
function algo_forms_field_key(array $field, $index = 0)
{
    if (!empty($field['key'])) {
        $key = sanitize_key((string) $field['key']);
        if ($key !== '') {
            return $key;
        }
    }
    $from_label = sanitize_title((string) ($field['label'] ?? ''));
    if ($from_label !== '') {
        return $from_label;
    }
    return 'field_' . (int) $index;
}

/**
 * @param array<int, array<string, mixed>> $fields
 * @return array<int, array<string, mixed>>
 */
function algo_forms_normalize_fields(array $fields)
{
    $normalized = array();
    $used = array();

    foreach ($fields as $index => $field) {
        if (!is_array($field)) {
            continue;
        }
        $key = algo_forms_field_key($field, $index);
        while (isset($used[$key])) {
            $key .= '-' . (int) $index;
        }
        $used[$key] = true;

        $type = sanitize_key((string) ($field['type'] ?? 'text'));
        if ($type === '') {
            $type = 'text';
        }

        $row = array(
            'key' => $key,
            'label' => sanitize_text_field((string) ($field['label'] ?? '')),
            'type' => $type,
            'required' => !empty($field['required']),
        );

        if ($type === 'select') {
            $options = isset($field['options']) && is_array($field['options']) ? $field['options'] : array();
            $row['options'] = array_values(array_filter(array_map(static function ($option) {
                return sanitize_text_field((string) $option);
            }, $options)));
        }

        $normalized[] = $row;
    }

    return $normalized;
}

/**
 * @param int $form_id
 * @return string
 */
function algo_forms_form_token($form_id)
{
    $payload = 'algo_form|' . (int) $form_id . '|' . home_url('/');
    return hash_hmac('sha256', $payload, wp_salt('nonce'));
}

/**
 * @param int    $form_id
 * @param string $token
 * @return bool
 */
function algo_forms_verify_form_token($form_id, $token)
{
    $token = is_string($token) ? trim($token) : '';
    if ($token === '') {
        return false;
    }
    return hash_equals(algo_forms_form_token($form_id), $token);
}

/**
 * @return bool
 */
function algo_forms_is_same_origin_submission()
{
    $home_host = wp_parse_url(home_url('/'), PHP_URL_HOST);
    if (!$home_host) {
        return false;
    }

    $page_url = isset($_POST['page_url']) ? wp_unslash($_POST['page_url']) : '';
    $page_host = is_string($page_url) ? wp_parse_url($page_url, PHP_URL_HOST) : '';
    if (is_string($page_host) && $page_host !== '' && strcasecmp($page_host, $home_host) === 0) {
        return true;
    }

    $referer = isset($_SERVER['HTTP_REFERER']) ? wp_unslash($_SERVER['HTTP_REFERER']) : '';
    $ref_host = is_string($referer) ? wp_parse_url($referer, PHP_URL_HOST) : '';
    return is_string($ref_host) && $ref_host !== '' && strcasecmp($ref_host, $home_host) === 0;
}

/**
 * @param string $raw
 * @return string[]
 */
function algo_forms_parse_email_list($raw)
{
    if (!is_string($raw) || $raw === '') {
        return array();
    }

    $trimmed = trim($raw);
    if ($trimmed !== '' && ($trimmed[0] === '{' || $trimmed[0] === '[')) {
        $decoded = json_decode($trimmed, true);
        if (is_array($decoded)) {
            return algo_forms_enabled_recipient_emails(algo_forms_normalize_recipient_entries($decoded));
        }
    }

    $parts = preg_split('/[\s,;]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
    $out = array();
    foreach ($parts as $p) {
        $e = sanitize_email($p);
        if ($e && is_email($e)) {
            $out[] = $e;
        }
    }
    return array_values(array_unique($out));
}

/**
 * Normalize recipient entries to [{email, enabled}, ...].
 *
 * Accepts legacy comma strings, string arrays, or structured arrays.
 *
 * @param mixed $raw
 * @return array<int, array{email:string,enabled:int}>
 */
function algo_forms_normalize_recipient_entries($raw)
{
    if (is_string($raw)) {
        $trimmed = trim($raw);
        if ($trimmed === '') {
            return array();
        }
        if ($trimmed[0] === '{' || $trimmed[0] === '[') {
            $decoded = json_decode($trimmed, true);
            if (is_array($decoded)) {
                $raw = $decoded;
            } else {
                $raw = algo_forms_parse_email_list($trimmed);
            }
        } else {
            $raw = algo_forms_parse_email_list($trimmed);
        }
    }

    if (!is_array($raw)) {
        return array();
    }

    // Config blob: { mode, recipients: [...] }
    if (isset($raw['recipients']) && is_array($raw['recipients'])) {
        $raw = $raw['recipients'];
    }

    $out = array();
    $seen = array();
    foreach ($raw as $item) {
        if (is_string($item)) {
            $email = sanitize_email(wp_unslash($item));
            $enabled = 1;
        } elseif (is_array($item)) {
            $email = sanitize_email(wp_unslash((string) ($item['email'] ?? '')));
            $enabled_raw = $item['enabled'] ?? 1;
            $enabled = in_array(strtolower((string) $enabled_raw), array('1', 'true', 'yes', 'on'), true) || $enabled_raw === 1 || $enabled_raw === true ? 1 : 0;
        } else {
            continue;
        }

        if (!$email || !is_email($email)) {
            continue;
        }
        $key = strtolower($email);
        if (isset($seen[$key])) {
            continue;
        }
        $seen[$key] = true;
        $out[] = array(
            'email' => $email,
            'enabled' => $enabled,
        );
    }

    return $out;
}

/**
 * @param array<int, array{email:string,enabled:int}> $entries
 * @return string[]
 */
function algo_forms_enabled_recipient_emails(array $entries)
{
    $out = array();
    foreach ($entries as $entry) {
        if (!empty($entry['enabled']) && !empty($entry['email']) && is_email($entry['email'])) {
            $out[] = $entry['email'];
        }
    }
    return array_values(array_unique($out));
}

/**
 * Sanitize recipient entries from POST:
 * emails[] + enabled[] parallel arrays, or legacy emails[].
 *
 * @param mixed $emails_input
 * @param mixed $enabled_input
 * @return array<int, array{email:string,enabled:int}>
 */
function algo_forms_sanitize_recipient_entries_from_post($emails_input, $enabled_input = null)
{
    if (!is_array($emails_input)) {
        if (is_string($emails_input)) {
            return algo_forms_normalize_recipient_entries($emails_input);
        }
        return array();
    }

    $enabled_map = array();
    if (is_array($enabled_input)) {
        foreach ($enabled_input as $email_key) {
            $email_key = strtolower(sanitize_email(wp_unslash((string) $email_key)));
            if ($email_key !== '') {
                $enabled_map[$email_key] = 1;
            }
        }
    }

    $out = array();
    $seen = array();
    foreach ($emails_input as $item) {
        if (is_array($item)) {
            $email = sanitize_email(wp_unslash((string) ($item['email'] ?? '')));
            $enabled = !empty($item['enabled']) ? 1 : 0;
        } else {
            $email = sanitize_email(wp_unslash((string) $item));
            // Checkbox list: only checked emails appear in enabled_input.
            $enabled = $enabled_input === null ? 1 : (isset($enabled_map[strtolower($email)]) ? 1 : 0);
        }

        if (!$email || !is_email($email)) {
            continue;
        }
        $key = strtolower($email);
        if (isset($seen[$key])) {
            continue;
        }
        $seen[$key] = true;
        $out[] = array(
            'email' => $email,
            'enabled' => $enabled,
        );
    }

    return $out;
}

/**
 * Legacy helper: email strings only (enabled ones when structured).
 *
 * @param mixed $input
 * @return string[]
 */
function algo_forms_sanitize_recipient_list($input)
{
    return algo_forms_enabled_recipient_emails(algo_forms_normalize_recipient_entries($input));
}

/**
 * @param array<int, array{email:string,enabled:int}>|string[] $emails
 * @return string
 * @deprecated Use structured array storage in options; kept for form column JSON.
 */
function algo_forms_recipients_to_storage(array $emails)
{
    $entries = algo_forms_normalize_recipient_entries($emails);
    return wp_json_encode(array(
        'mode' => 'custom',
        'recipients' => $entries,
    ));
}

/**
 * Decode form notify_emails column (legacy CSV or JSON config).
 *
 * @param string|null $raw
 * @return array{mode:string,recipients:array<int,array{email:string,enabled:int}>}
 */
function algo_forms_decode_form_notify_config($raw)
{
    $defaults = array(
        'mode' => 'global',
        'recipients' => array(),
    );

    if (!is_string($raw) || trim($raw) === '') {
        return $defaults;
    }

    $trimmed = trim($raw);
    if ($trimmed[0] === '{') {
        $decoded = json_decode($trimmed, true);
        if (is_array($decoded)) {
            $mode = isset($decoded['mode']) ? sanitize_key((string) $decoded['mode']) : 'custom';
            if (!in_array($mode, array('global', 'custom'), true)) {
                $mode = 'custom';
            }
            return array(
                'mode' => $mode,
                'recipients' => algo_forms_normalize_recipient_entries($decoded['recipients'] ?? $decoded),
            );
        }
    }

    // Legacy comma-separated form-specific emails meant "add on top of global".
    // Keep them as custom-only list so routing stays predictable going forward.
    $emails = algo_forms_parse_email_list($trimmed);
    if (!$emails) {
        return $defaults;
    }

    return array(
        'mode' => 'custom',
        'recipients' => algo_forms_normalize_recipient_entries($emails),
    );
}

/**
 * Encode form notify config for DB.
 *
 * @param string                                                   $mode
 * @param array<int, array{email:string,enabled:int}> $recipients
 * @return string
 */
function algo_forms_encode_form_notify_config($mode, array $recipients)
{
    $mode = sanitize_key((string) $mode);
    if (!in_array($mode, array('global', 'custom'), true)) {
        $mode = 'global';
    }

    return wp_json_encode(array(
        'mode' => $mode,
        'recipients' => algo_forms_normalize_recipient_entries($recipients),
    ));
}

/**
 * Global company notification recipients that are enabled.
 *
 * @return string[]
 */
function algo_forms_get_company_recipients()
{
    $opts = algo_forms_get_options();
    return algo_forms_enabled_recipient_emails(algo_forms_normalize_recipient_entries($opts['recipients'] ?? array()));
}

/**
 * All global recipient entries (including disabled).
 *
 * @return array<int, array{email:string,enabled:int}>
 */
function algo_forms_get_company_recipient_entries()
{
    $opts = algo_forms_get_options();
    return algo_forms_normalize_recipient_entries($opts['recipients'] ?? array());
}

/**
 * Render add/remove UI for notification emails with per-email enable toggle.
 *
 * @param array<int, array{email:string,enabled:int}>|string[] $entries
 * @param string                                               $input_base e.g. algo_forms_recipients or notify_emails
 * @param string                                               $list_id
 * @param array                                                $args
 * @return void
 */
function algo_forms_render_recipients_manager($entries, $input_base, $list_id, $args = array())
{
    $empty_note = isset($args['empty_note']) ? (string) $args['empty_note'] : '';
    $add_placeholder = isset($args['add_placeholder'])
        ? (string) $args['add_placeholder']
        : 'name@algorisys.com';
    $hint = isset($args['hint'])
        ? (string) $args['hint']
        : __('Add one address at a time. Use “Receive” to include or exclude someone without deleting them. Click Save changes to keep the list.', 'algo-forms');

    // Back-compat: old callers passed emails[] as second arg name.
    if (substr($input_base, -2) === '[]') {
        $input_base = substr($input_base, 0, -2);
    }

    $entries = algo_forms_normalize_recipient_entries($entries);
    $email_name = $input_base . '[emails][]';
    $enabled_name = $input_base . '[enabled][]';
    ?>
    <div class="algo-recipients-manager" data-list-id="<?php echo esc_attr($list_id); ?>" data-input-base="<?php echo esc_attr($input_base); ?>">
        <ul class="algo-recipients-list" id="<?php echo esc_attr($list_id); ?>">
            <?php foreach ($entries as $entry) : ?>
                <li class="algo-recipients-item<?php echo empty($entry['enabled']) ? ' is-disabled' : ''; ?>">
                    <input type="hidden" name="<?php echo esc_attr($email_name); ?>" value="<?php echo esc_attr($entry['email']); ?>">
                    <span class="algo-recipients-email"><?php echo esc_html($entry['email']); ?></span>
                    <label class="algo-recipients-toggle">
                        <input type="checkbox" name="<?php echo esc_attr($enabled_name); ?>" value="<?php echo esc_attr($entry['email']); ?>" <?php checked(!empty($entry['enabled'])); ?>>
                        <?php esc_html_e('Receive', 'algo-forms'); ?>
                    </label>
                    <button type="button" class="button-link-delete algo-recipients-remove"><?php esc_html_e('Remove', 'algo-forms'); ?></button>
                </li>
            <?php endforeach; ?>
        </ul>

        <?php if ($empty_note !== '') : ?>
            <p class="algo-recipients-empty description" <?php echo $entries ? 'hidden' : ''; ?>><?php echo esc_html($empty_note); ?></p>
        <?php endif; ?>

        <div class="algo-recipients-add">
            <input type="email" class="regular-text algo-recipients-new" placeholder="<?php echo esc_attr($add_placeholder); ?>" autocomplete="email">
            <button type="button" class="button algo-recipients-add-btn"><?php esc_html_e('Add email', 'algo-forms'); ?></button>
        </div>
        <p class="description algo-recipients-hint"><?php echo esc_html($hint); ?></p>
    </div>
    <?php
}

/**
 * Shared admin CSS/JS for the recipients manager.
 *
 * @return void
 */
function algo_forms_recipients_manager_assets()
{
    static $printed = false;
    if ($printed) {
        return;
    }
    $printed = true;
    ?>
    <style>
        .algo-recipients-manager { max-width: 640px; }
        .algo-recipients-list { margin: 0 0 10px; padding: 0; list-style: none; border: 1px solid #c3c4c7; border-radius: 4px; background: #fff; }
        .algo-recipients-list:empty { display: none; }
        .algo-recipients-item { display: flex; align-items: center; gap: 12px; margin: 0; padding: 10px 12px; border-bottom: 1px solid #dcdcde; }
        .algo-recipients-item:last-child { border-bottom: 0; }
        .algo-recipients-item.is-disabled .algo-recipients-email { opacity: 0.55; text-decoration: line-through; }
        .algo-recipients-email { font-weight: 600; word-break: break-all; flex: 1 1 auto; }
        .algo-recipients-toggle { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-size: 13px; color: #1d2327; }
        .algo-recipients-add { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
        .algo-recipients-add .algo-recipients-new { min-width: 260px; }
        .algo-recipients-empty { margin: 0 0 8px; }
        .algo-company-recipients-card { background: #fff; border: 1px solid #c3c4c7; border-left: 4px solid #2271b1; border-radius: 4px; padding: 16px 18px; margin: 16px 0 24px; max-width: 760px; }
        .algo-company-recipients-card h2 { margin: 0 0 6px; font-size: 1.15em; }
        .algo-company-recipients-card > .description { margin-top: 0; margin-bottom: 14px; }
        .algo-recipients-summary { margin: 8px 0 0; }
        .algo-notify-mode { margin: 0 0 12px; }
        .algo-notify-mode label { display: block; margin: 0 0 6px; }
        .algo-notify-custom-wrap[hidden] { display: none !important; }
    </style>
    <script>
    (function () {
        function normalize(email) {
            return String(email || '').trim().toLowerCase();
        }
        function isValid(email) {
            return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
        }
        function refreshEmpty(manager) {
            var list = manager.querySelector('.algo-recipients-list');
            var empty = manager.querySelector('.algo-recipients-empty');
            if (!empty || !list) return;
            empty.hidden = list.children.length > 0;
            list.style.display = list.children.length ? '' : 'none';
        }
        function addEmail(manager, raw) {
            var email = normalize(raw);
            if (!isValid(email)) {
                window.alert(<?php echo wp_json_encode(__('Enter a valid email address.', 'algo-forms')); ?>);
                return;
            }
            var list = manager.querySelector('.algo-recipients-list');
            var inputBase = manager.getAttribute('data-input-base') || 'recipients';
            var existing = Array.prototype.map.call(list.querySelectorAll('input[type="hidden"]'), function (el) {
                return normalize(el.value);
            });
            if (existing.indexOf(email) !== -1) {
                window.alert(<?php echo wp_json_encode(__('That email is already in the list.', 'algo-forms')); ?>);
                return;
            }
            var li = document.createElement('li');
            li.className = 'algo-recipients-item';
            li.innerHTML =
                '<input type="hidden" name="' + inputBase + '[emails][]" value="">' +
                '<span class="algo-recipients-email"></span>' +
                '<label class="algo-recipients-toggle"><input type="checkbox" name="' + inputBase + '[enabled][]" value="" checked> <?php echo esc_js(__('Receive', 'algo-forms')); ?></label>' +
                '<button type="button" class="button-link-delete algo-recipients-remove"><?php echo esc_js(__('Remove', 'algo-forms')); ?></button>';
            li.querySelector('input[type="hidden"]').value = email;
            li.querySelector('input[type="checkbox"]').value = email;
            li.querySelector('.algo-recipients-email').textContent = email;
            list.appendChild(li);
            list.style.display = '';
            refreshEmpty(manager);
        }
        document.addEventListener('change', function (e) {
            var toggle = e.target.closest('.algo-recipients-toggle input[type="checkbox"]');
            if (!toggle) return;
            var item = toggle.closest('.algo-recipients-item');
            if (item) item.classList.toggle('is-disabled', !toggle.checked);
        });
        document.addEventListener('click', function (e) {
            var removeBtn = e.target.closest('.algo-recipients-remove');
            if (removeBtn) {
                var manager = removeBtn.closest('.algo-recipients-manager');
                removeBtn.closest('.algo-recipients-item').remove();
                if (manager) refreshEmpty(manager);
                return;
            }
            var addBtn = e.target.closest('.algo-recipients-add-btn');
            if (addBtn) {
                var manager = addBtn.closest('.algo-recipients-manager');
                var input = manager.querySelector('.algo-recipients-new');
                addEmail(manager, input.value);
                input.value = '';
                input.focus();
            }
        });
        document.addEventListener('keydown', function (e) {
            if (e.key !== 'Enter') return;
            if (!e.target.classList.contains('algo-recipients-new')) return;
            e.preventDefault();
            var manager = e.target.closest('.algo-recipients-manager');
            addEmail(manager, e.target.value);
            e.target.value = '';
        });
        document.addEventListener('change', function (e) {
            if (!e.target.name || e.target.name.indexOf('notify_mode') === -1) return;
            var wrap = document.querySelector('.algo-notify-custom-wrap');
            if (!wrap) return;
            wrap.hidden = e.target.value !== 'custom';
        });
    })();
    </script>
    <?php
}

/**
 * @param array  $opts
 * @param string $reply_to
 * @return string[]
 */
function algo_forms_notification_headers($opts, $reply_to = '')
{
    $headers = array('Content-Type: text/html; charset=UTF-8');

    $our_smtp = function_exists('algo_forms_smtp_is_ready') && algo_forms_smtp_is_ready($opts);
    $external_smtp = function_exists('algo_forms_external_smtp_plugin_active') && algo_forms_external_smtp_plugin_active();
    // Authenticated SMTP: avoid Reply-To mismatches that some providers reject.
    // From is applied in phpmailer_init for our SMTP; skip header From when external owns it.
    $skip_from_header = $our_smtp || ($external_smtp && !$our_smtp);
    $skip_reply_to = $our_smtp || $external_smtp;

    if (!$skip_from_header) {
        $from_name = trim((string) ($opts['from_name'] ?? ''));
        $from_email = trim((string) ($opts['from_email'] ?? ''));
        if ($from_email !== '' && is_email($from_email)) {
            if ($from_name !== '') {
                $safe_name = str_replace(array("\r", "\n", '"'), '', sanitize_text_field($from_name));
                $headers[] = 'From: ' . sprintf('"%s" <%s>', $safe_name, $from_email);
            } else {
                $headers[] = 'From: ' . $from_email;
            }
        }
    }

    if (!$skip_reply_to) {
        $reply_to = trim((string) $reply_to);
        if ($reply_to !== '' && is_email($reply_to)) {
            $headers[] = 'Reply-To: ' . $reply_to;
        }
    }

    return $headers;
}

/**
 * Whether mail delivery is under SMTP control (ours or an external plugin).
 *
 * @return bool
 */
function algo_forms_mail_is_smtp_controlled()
{
    if (function_exists('algo_forms_smtp_is_ready') && algo_forms_smtp_is_ready()) {
        return true;
    }
    return function_exists('algo_forms_external_smtp_plugin_active') && algo_forms_external_smtp_plugin_active();
}

/**
 * Persist a short mail log for the Email & notifications admin screen.
 *
 * @param array<string,mixed> $entry
 * @return void
 */
function algo_forms_record_mail_log(array $entry)
{
    $entry['time'] = wp_date('Y-m-d H:i:s');
    update_option('algo_forms_last_mail_log', $entry, false);
}

/**
 * @param string               $title
 * @param string               $intro
 * @param array<string,mixed>  $rows
 * @param string               $footer_note
 * @return string
 */
function algo_forms_render_email_html($title, $intro, $rows, $footer_note = '')
{
    $safe_title = esc_html($title);
    $safe_intro = wp_kses_post(wpautop(esc_html($intro)));
    $safe_footer = $footer_note !== '' ? wp_kses_post(wpautop(esc_html($footer_note))) : '';

    $rows_html = '';
    foreach ($rows as $label => $value) {
        $rows_html .= '<tr>';
        $rows_html .= '<td style="padding:10px 12px;border:1px solid #e2e8f0;font-weight:600;color:#0f172a;width:32%;">' . esc_html((string) $label) . '</td>';
        $rows_html .= '<td style="padding:10px 12px;border:1px solid #e2e8f0;color:#1e293b;">' . nl2br(esc_html((string) $value)) . '</td>';
        $rows_html .= '</tr>';
    }

    return '<!doctype html><html><body style="margin:0;padding:24px;background:#f8fafc;font-family:Arial,sans-serif;">'
        . '<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="max-width:700px;margin:0 auto;background:#ffffff;border:1px solid #e2e8f0;">'
        . '<tr><td style="padding:18px 20px;background:#1e293b;color:#fff;font-size:20px;font-weight:700;">' . $safe_title . '</td></tr>'
        . '<tr><td style="padding:18px 20px;font-size:14px;line-height:1.6;color:#334155;">' . $safe_intro . '</td></tr>'
        . '<tr><td style="padding:0 20px 20px;"><table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="border-collapse:collapse;">' . $rows_html . '</table></td></tr>'
        . ($safe_footer !== '' ? '<tr><td style="padding:0 20px 20px;font-size:13px;color:#64748b;">' . $safe_footer . '</td></tr>' : '')
        . '</table></body></html>';
}

/**
 * @param string|string[] $to
 * @param string          $subject
 * @param string          $body
 * @param string[]        $headers
 * @param string          $log_context
 * @return array{0:bool,1:string}
 */
function algo_forms_wp_mail_send($to, $subject, $body, $headers = array(), $log_context = '')
{
    $to_str = is_array($to) ? implode(', ', $to) : (string) $to;

    if (defined('ALGO_FORMS_LOG_MAIL_BODY') && ALGO_FORMS_LOG_MAIL_BODY) {
        $h = is_array($headers) ? implode("\n", $headers) : '';
        error_log('[algo-forms] Dev mail log' . ($log_context ? " ({$log_context})" : '') . "\nTo: {$to_str}\nSubject: {$subject}\nHeaders:\n{$h}\n\n{$body}\n----------");
    }

    if (defined('ALGO_FORMS_SKIP_MAIL_SEND') && ALGO_FORMS_SKIP_MAIL_SEND) {
        return array(true, '');
    }

    $detail = '';
    $on_fail = function ($err) use (&$detail) {
        if (!is_wp_error($err)) {
            return;
        }
        $detail = $err->get_error_message();
        $data = $err->get_error_data();
        if (is_object($data) && isset($data->ErrorInfo)) {
            $detail .= ' — ' . $data->ErrorInfo;
        }
    };
    add_action('wp_mail_failed', $on_fail, 10, 1);
    $sent = wp_mail($to, $subject, $body, $headers);
    remove_action('wp_mail_failed', $on_fail, 10);

    if (!$sent) {
        $log = 'algo-forms: wp_mail failed';
        if ($log_context !== '') {
            $log .= ' (' . $log_context . ')';
        }
        if ($detail !== '') {
            $log .= ': ' . $detail;
        }
        error_log($log);
    }

    if (function_exists('algo_forms_delivery_log_write') && function_exists('algo_forms_parse_mail_context')) {
        $ids = algo_forms_parse_mail_context($log_context);
        algo_forms_delivery_log_write(array(
            'ok' => (bool) $sent,
            'to_email' => $to_str,
            'subject' => $subject,
            'detail' => $detail,
            'context' => $log_context,
            'form_id' => $ids['form_id'],
            'submission_id' => $ids['submission_id'],
        ));
    }

    return array($sent, $detail);
}

/**
 * @param array<string,mixed>          $form_data
 * @param array<int,array<string,mixed>> $fields_def
 * @return string
 */
function algo_forms_reply_to_from_data($form_data, $fields_def)
{
    $fields_def = algo_forms_normalize_fields(is_array($fields_def) ? $fields_def : array());

    foreach ($fields_def as $index => $field) {
        if (($field['type'] ?? '') !== 'email') {
            continue;
        }
        $label = $field['label'] ?? '';
        $field_key = algo_forms_field_key($field, $index);
        foreach (array($label, $field_key) as $cand_key) {
            if ($cand_key !== '' && isset($form_data[$cand_key])) {
                $cand = sanitize_email((string) $form_data[$cand_key]);
                if ($cand && is_email($cand)) {
                    return $cand;
                }
            }
        }
    }

    foreach ($form_data as $label => $value) {
        if ($label === 'Page' || $label === 'Plugin' || !is_string($value)) {
            continue;
        }
        if (stripos((string) $label, 'email') !== false) {
            $cand = sanitize_email($value);
            if ($cand && is_email($cand)) {
                return $cand;
            }
        }
    }

    return '';
}

/**
 * Resolve who should receive the company notification for a form.
 *
 * - mode=global (default): enabled global recipients only
 * - mode=custom: enabled form-specific recipients only
 * Falls back to WP admin email only when nothing is configured.
 *
 * @param object|null $form
 * @return string[]
 */
function algo_forms_resolve_company_recipients($form = null)
{
    $to = array();

    if ($form) {
        $config = algo_forms_decode_form_notify_config($form->notify_emails ?? '');
        if (($config['mode'] ?? 'global') === 'custom') {
            $to = algo_forms_enabled_recipient_emails($config['recipients']);
        } else {
            $to = algo_forms_get_company_recipients();
        }
    } else {
        $to = algo_forms_get_company_recipients();
    }

    $to = array_values(array_unique(array_filter($to)));

    if (empty($to)) {
        $admin = get_option('admin_email');
        if ($admin && is_email($admin)) {
            $to = array($admin);
        }
    }

    return $to;
}

/**
 * @param object                       $form
 * @param array<string,mixed>          $form_data
 * @param array<int,array<string,mixed>> $fields_def
 * @return bool|null
 */
function algo_forms_send_notification($form, $form_data, $fields_def, $submission_id = 0)
{
    $opts = algo_forms_get_options();
    $submission_id = (int) $submission_id;
    $ctx_suffix = ' form id ' . (int) $form->id . ($submission_id ? (' submission id ' . $submission_id) : '');

    if (empty($opts['send_notifications'])) {
        algo_forms_record_mail_log(array(
            'ok' => false,
            'type' => 'company',
            'detail' => 'Company notifications are disabled in Algo Forms settings.',
            'recipients' => array(),
        ));
        return null;
    }

    $to = algo_forms_resolve_company_recipients($form);
    if (empty($to)) {
        algo_forms_record_mail_log(array(
            'ok' => false,
            'type' => 'company',
            'detail' => 'No company recipients configured.',
            'recipients' => array(),
        ));
        error_log('algo-forms: company notification skipped — no recipients configured');
        return null;
    }

    $site = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
    $subject_tpl = !empty($form->email_subject) ? $form->email_subject : ($opts['subject_template'] ?? '');
    if ($subject_tpl === '') {
        $subject_tpl = 'New contact: {form_title} — {site_name}';
    }
    $subject = str_replace(
        array('{form_title}', '{form_name}', '{site_name}'),
        array($form->form_title, $form->form_name, $site),
        $subject_tpl
    );
    $subject = sanitize_text_field($subject);
    if ($subject === '') {
        $subject = sprintf('New contact: %s', $form->form_title);
    }

    $reply = algo_forms_reply_to_from_data($form_data, $fields_def);

    $admin_rows = $form_data;
    if ($reply !== '') {
        // Keep reply address in the body so SMTP Auth (e.g. Yahoo) is not broken by Reply-To.
        $admin_rows = array_merge(
            array('Reply to visitor' => $reply),
            $admin_rows
        );
    }
    $admin_rows['Site'] = home_url('/');
    $admin_rows['Date'] = wp_date('Y-m-d H:i:s');
    $message = algo_forms_render_email_html(
        sprintf('New submission: %s', $form->form_title),
        sprintf('A new form submission was received from %s.', $site),
        $admin_rows
    );

    // No Reply-To header when SMTP-controlled — that was blocking company mail.
    $headers = algo_forms_notification_headers($opts, '');

    $any_sent = false;
    $failed = array();
    $sent_to = array();

    foreach ($to as $recipient) {
        list($sent, $detail) = algo_forms_wp_mail_send(
            $recipient,
            $subject,
            $message,
            $headers,
            'company notify' . $ctx_suffix . ' → ' . $recipient
        );
        if ($sent) {
            $any_sent = true;
            $sent_to[] = $recipient;
        } else {
            $failed[] = $recipient . ($detail !== '' ? ' (' . $detail . ')' : '');
        }
    }

    algo_forms_record_mail_log(array(
        'ok' => $any_sent && !$failed,
        'type' => 'company',
        'detail' => $failed
            ? ('Failed: ' . implode('; ', $failed) . ($sent_to ? ' | Sent: ' . implode(', ', $sent_to) : ''))
            : ('Sent to: ' . implode(', ', $sent_to)),
        'recipients' => $to,
        'subject' => $subject,
    ));

    if ($failed) {
        error_log('algo-forms: company notification failed for: ' . implode('; ', $failed));
    } else {
        error_log('algo-forms: company notification sent to: ' . implode(', ', $to));
    }

    $visitor_email = $reply;
    if (!empty($opts['send_visitor_copy']) && $visitor_email !== '') {
        $visitor_subject_tpl = (string) ($opts['visitor_subject_template'] ?? '');
        if ($visitor_subject_tpl === '') {
            $visitor_subject_tpl = 'Thanks for contacting {site_name}';
        }
        $visitor_subject = sanitize_text_field(str_replace(
            array('{form_title}', '{form_name}', '{site_name}'),
            array($form->form_title, $form->form_name, $site),
            $visitor_subject_tpl
        ));

        $messages = algo_forms_get_form_messages($form);
        $visitor_intro = (string) ($messages['success_message'] ?? '');
        if ($visitor_intro === '') {
            $visitor_intro = (string) ($opts['visitor_intro'] ?? '');
        }

        $visitor_rows = $form_data;
        unset($visitor_rows['Page']);
        $visitor_message = algo_forms_render_email_html(
            sprintf('Thank you — %s', $site),
            $visitor_intro,
            $visitor_rows,
            'This is an automated acknowledgement.'
        );
        list($visitor_sent, $visitor_detail) = algo_forms_wp_mail_send(
            $visitor_email,
            $visitor_subject,
            $visitor_message,
            algo_forms_notification_headers($opts, ''),
            'visitor copy' . $ctx_suffix
        );

        // Keep company log as primary; append visitor result.
        $log = get_option('algo_forms_last_mail_log', array());
        if (!is_array($log)) {
            $log = array();
        }
        $log['visitor'] = $visitor_sent
            ? ('Visitor copy sent to ' . $visitor_email)
            : ('Visitor copy FAILED for ' . $visitor_email . ($visitor_detail !== '' ? ': ' . $visitor_detail : ''));
        update_option('algo_forms_last_mail_log', $log, false);
    }

    return $any_sent;
}
