<?php
/**
 * Easy WP SMTP Importer.
 *
 * Imports settings from the Easy WP SMTP plugin into NimblyMail.
 *
 * @since 1.0.0
 *
 * @package NimblyMail\SMTP
 */

namespace NimblyMail\SMTP\Import;

defined( 'ABSPATH' ) || exit;

/**
 * Class EasyWpSmtpImporter
 *
 * Reads settings stored by the Easy WP SMTP plugin (option key `easy_wp_smtp`
 * or the legacy `swpsmtp_options`) and maps them to the NimblyMail options format.
 *
 * @since 1.0.0
 * @since 1.0.4 Added Brevo credential mapping.
 * @since 1.0.6 Added Outlook / Microsoft 365 credential mapping. Debug-event
 *              retention is now converted from the source's seconds to
 *              NimblyMail's days. A source with no mailer key at all no
 *              longer defaults to PHP mail() and now leaves mail.mailer
 *              unset instead.
 */
class EasyWpSmtpImporter extends AbstractImporter {

    /**
     * Legacy option key used by older Easy WP SMTP releases.
     *
     * @since 1.0.0
     *
     * @var string
     */
    private const LEGACY_OPTION_KEY = 'swpsmtp_options';

    /**
     * Pro-edition plugin basename for active-plugin detection.
     *
     * @since 1.0.0
     *
     * @var string
     */
    private const PRO_PLUGIN_BASENAME = 'easy-wp-smtp-pro/easy-wp-smtp.php';

    /**
     * Get the importer slug identifier.
     *
     * @since 1.0.0
     *
     * @return string
     */
    public function get_slug(): string {
        return 'easy-wp-smtp';
    }

    /**
     * Get the human-readable name of the source plugin.
     *
     * @since 1.0.0
     *
     * @return string
     */
    public function get_name(): string {
        return __( 'Easy WP SMTP', 'nimblymail-smtp' );
    }

    /**
     * Get a short description for the importer card UI.
     *
     * @since 1.0.0
     *
     * @return string
     */
    public function get_description(): string {
        return __( 'Import your email settings from Easy WP SMTP.', 'nimblymail-smtp' );
    }

    /**
     * Get the wp_options key for the source plugin settings.
     *
     * @since 1.0.0
     *
     * @return string
     */
    public function get_option_key(): string {
        return 'easy_wp_smtp';
    }

    /**
     * Get the plugin basename for active-plugin detection.
     *
     * @since 1.0.0
     *
     * @return string
     */
    public function get_plugin_basename(): string {
        return 'easy-wp-smtp/easy-wp-smtp.php';
    }

    /**
     * Check if the source plugin is active and has importable data.
     *
     * Considers either the free or Pro edition active in any scope (current
     * site or network), then verifies that the primary option key
     * (`easy_wp_smtp`) or legacy fallback (`swpsmtp_options`) is readable
     * via the network/main-site fallback chain.
     *
     * @since 1.0.0
     *
     * @return bool
     */
    public function is_available(): bool {
        $basenames = array(
            $this->get_plugin_basename(),
            self::PRO_PLUGIN_BASENAME,
        );

        if ( ! $this->is_source_plugin_active( $basenames ) ) {
            return false;
        }

        return ! empty( $this->get_source_data() );
    }

    /**
     * Get the raw source plugin settings from the database.
     *
     * Tries the primary option key first and falls back to the legacy key
     * (`swpsmtp_options`) when no data is found under the primary key. Each
     * lookup uses `read_source_option()` so multisite network/main-site
     * fallback applies to both keys.
     *
     * @since 1.0.0
     *
     * @return array
     */
    public function get_source_data(): array {
        $data = $this->read_source_option( $this->get_option_key() );

        if ( empty( $data ) ) {
            $data = $this->read_source_option( self::LEGACY_OPTION_KEY );
        }

        return $data;
    }

    /**
     * Map Easy WP SMTP source settings to the NimblyMail options format.
     *
     * Processes the raw option array read from the database and returns a
     * structured result containing the mapped settings, any warnings, and
     * a list of explicitly skipped fields. Easy WP SMTP only encrypts
     * `smtp.pass` at rest; every other credential (SES secret, Gmail client
     * secret, SendLayer/Resend/Brevo API keys) is stored in plain text and is
     * imported verbatim.
     *
     * Setting groups mapped:
     * - `mail`        – from address/name, force flags, return-path, mailer.
     * - `smtp`        – host/port/encryption/autotls/auth/user (pass is encrypted, skipped).
     * - `ses`         – access key id, secret access key, region.
     * - `gmail`       – client id, client secret (OAuth tokens require re-auth).
     * - `outlook`     – client id, client secret (OAuth tokens require re-auth).
     * - `sendlayer`   – api key.
     * - `resend`      – api key.
     * - `brevo`       – api key.
     * - `general`     – do_not_send, debug events retention (converted from seconds to days), uninstall flag.
     * - `logs`        – enabled flag.
     * - `alerts`      – enabled flag plus email recipients (cc for additional).
     *
     * @since 1.0.0
     * @since 1.0.4 Brevo credentials are now carried across. A mailer is only
     *              saved when its credentials actually came with it, and a
     *              source mailer NimblyMail cannot handle now raises a warning
     *              instead of being passed over in silence.
     * @since 1.0.6 Outlook credentials are now carried across. Debug-event
     *              retention is now converted from the source's seconds to
     *              NimblyMail's days instead of being copied verbatim. A
     *              source with no mailer key at all now leaves mail.mailer
     *              unset instead of defaulting to PHP mail() and silently
     *              overwriting a working configuration.
     *
     * @param array $source_data Raw Easy WP SMTP options array.
     *
     * @return array{settings: array, warnings: array, skipped: array}
     */
    protected function map_settings( array $source_data ): array {
        $settings = array();
        $warnings = array();
        $skipped  = array();

        // ------------------------------------------------------------------ //
        // Mail (from / general) settings.
        // ------------------------------------------------------------------ //
        $mail_source   = isset( $source_data['mail'] ) && is_array( $source_data['mail'] )
            ? $source_data['mail']
            : array();
        $mail_settings = array();

        if ( ! empty( $mail_source['from_email'] ) ) {
            $mail_settings['from_email'] = sanitize_email( $mail_source['from_email'] );
        }

        if ( ! empty( $mail_source['from_name'] ) ) {
            $mail_settings['from_name'] = sanitize_text_field( $mail_source['from_name'] );
        }

        if ( isset( $mail_source['from_email_force'] ) ) {
            $mail_settings['from_email_force'] = $this->to_bool( $mail_source['from_email_force'] );
        }

        if ( isset( $mail_source['from_name_force'] ) ) {
            $mail_settings['from_name_force'] = $this->to_bool( $mail_source['from_name_force'] );
        }

        if ( isset( $mail_source['return_path'] ) ) {
            $mail_settings['return_path'] = $this->to_bool( $mail_source['return_path'] );
        }

        $source_mailer = isset( $mail_source['mailer'] ) ? sanitize_key( $mail_source['mailer'] ) : null;
        $mapped_mailer = null;

        if ( null !== $source_mailer ) {
            $mapped_mailer = $this->map_mailer_slug( $source_mailer );

            if ( null !== $mapped_mailer ) {
                $mail_settings['mailer'] = $mapped_mailer;
            } else {
                $this->skip_unsupported_mailer( $source_mailer, $warnings, $skipped );
            }
        }

        if ( ! empty( $mail_settings ) ) {
            $settings['mail'] = $mail_settings;
        }

        // ------------------------------------------------------------------ //
        // SMTP settings.
        // ------------------------------------------------------------------ //
        if ( 'smtp' === $mapped_mailer ) {
            $smtp_source   = isset( $source_data['smtp'] ) && is_array( $source_data['smtp'] )
                ? $source_data['smtp']
                : array();
            $smtp_settings = array();

            if ( ! empty( $smtp_source['host'] ) ) {
                $smtp_settings['host'] = sanitize_text_field( $smtp_source['host'] );
            }

            if ( isset( $smtp_source['port'] ) ) {
                $smtp_settings['port'] = absint( $smtp_source['port'] );
            }

            if ( ! empty( $smtp_source['encryption'] ) ) {
                $smtp_settings['encryption'] = sanitize_key( $smtp_source['encryption'] );
            }

            if ( isset( $smtp_source['autotls'] ) ) {
                $smtp_settings['autotls'] = $this->to_bool( $smtp_source['autotls'] );
            }

            if ( isset( $smtp_source['auth'] ) ) {
                $smtp_settings['auth'] = $this->to_bool( $smtp_source['auth'] );
            }

            if ( ! empty( $smtp_source['user'] ) ) {
                $smtp_settings['user'] = sanitize_text_field( $smtp_source['user'] );
            }

            // SMTP password is the only field Easy WP SMTP encrypts at rest.
            $this->skip_encrypted( __( 'SMTP Password', 'nimblymail-smtp' ), 'smtp.pass', $warnings, $skipped );

            if ( ! empty( $smtp_settings ) ) {
                $settings['smtp'] = $smtp_settings;
            }
        }

        // ------------------------------------------------------------------ //
        // Amazon SES settings (all plain text in source).
        // ------------------------------------------------------------------ //
        if ( 'ses' === $mapped_mailer ) {
            $ses_source   = isset( $source_data['amazonses'] ) && is_array( $source_data['amazonses'] )
                ? $source_data['amazonses']
                : array();
            $ses_settings = array();

            if ( ! empty( $ses_source['client_id'] ) ) {
                $ses_settings['access_key_id'] = sanitize_text_field( $ses_source['client_id'] );
            }

            if ( ! empty( $ses_source['client_secret'] ) ) {
                $ses_settings['secret_access_key'] = sanitize_text_field( $ses_source['client_secret'] );
            }

            if ( ! empty( $ses_source['region'] ) ) {
                $ses_settings['region'] = sanitize_text_field( $ses_source['region'] );
            }

            if ( ! empty( $ses_settings ) ) {
                $settings['ses'] = $ses_settings;
            }
        }

        // ------------------------------------------------------------------ //
        // Gmail OAuth settings (client_id/secret are plain; tokens require re-auth).
        // ------------------------------------------------------------------ //
        if ( 'gmail' === $mapped_mailer ) {
            $gmail_source   = isset( $source_data['gmail'] ) && is_array( $source_data['gmail'] )
                ? $source_data['gmail']
                : array();
            $gmail_settings = array();

            if ( ! empty( $gmail_source['client_id'] ) ) {
                $gmail_settings['client_id'] = sanitize_text_field( $gmail_source['client_id'] );
            }

            if ( ! empty( $gmail_source['client_secret'] ) ) {
                $gmail_settings['client_secret'] = sanitize_text_field( $gmail_source['client_secret'] );
            }

            $warnings[] = array(
                'field'   => 'gmail.oauth',
                'message' => __(
                    'Gmail OAuth access and refresh tokens cannot be transferred between plugins. After importing, please reconnect your Google account inside NimblyMail settings.',
                    'nimblymail-smtp'
                ),
            );

            if ( ! empty( $gmail_settings ) ) {
                $settings['gmail'] = $gmail_settings;
            }
        }

        // ------------------------------------------------------------------ //
        // Outlook / Microsoft 365 OAuth settings (client_id/secret plain in source).
        // Easy WP SMTP has no equivalent stored option for NimblyMail's
        // outlook.tenant, so it is left at its default.
        // ------------------------------------------------------------------ //
        if ( 'outlook' === $mapped_mailer ) {
            $outlook_source   = isset( $source_data['outlook'] ) && is_array( $source_data['outlook'] )
                ? $source_data['outlook']
                : array();
            $outlook_settings = array();

            if ( ! empty( $outlook_source['client_id'] ) ) {
                $outlook_settings['client_id'] = sanitize_text_field( $outlook_source['client_id'] );
            }

            if ( ! empty( $outlook_source['client_secret'] ) ) {
                $outlook_settings['client_secret'] = sanitize_text_field( $outlook_source['client_secret'] );
            }

            $warnings[] = array(
                'field'   => 'outlook.oauth',
                'message' => __(
                    'Outlook OAuth access and refresh tokens cannot be transferred between plugins. After importing, please reconnect your Microsoft account inside NimblyMail settings.',
                    'nimblymail-smtp'
                ),
            );

            if ( ! empty( $outlook_settings ) ) {
                $settings['outlook'] = $outlook_settings;
            }
        }

        // ------------------------------------------------------------------ //
        // SendLayer settings (api_key plain in source).
        // ------------------------------------------------------------------ //
        if ( 'sendlayer' === $mapped_mailer ) {
            $sendlayer_source = isset( $source_data['sendlayer'] ) && is_array( $source_data['sendlayer'] )
                ? $source_data['sendlayer']
                : array();

            if ( ! empty( $sendlayer_source['api_key'] ) ) {
                $settings['sendlayer'] = array(
                    'api_key' => sanitize_text_field( $sendlayer_source['api_key'] ),
                );
            }
        }

        // ------------------------------------------------------------------ //
        // Resend settings (api_key plain in source).
        // ------------------------------------------------------------------ //
        if ( 'resend' === $mapped_mailer ) {
            $resend_source = isset( $source_data['resend'] ) && is_array( $source_data['resend'] )
                ? $source_data['resend']
                : array();

            if ( ! empty( $resend_source['api_key'] ) ) {
                $settings['resend'] = array(
                    'api_key' => sanitize_text_field( $resend_source['api_key'] ),
                );
            }
        }

        // ------------------------------------------------------------------ //
        // Brevo settings (api_key plain in source, under sendinblue).
        // ------------------------------------------------------------------ //
        if ( 'brevo' === $mapped_mailer ) {
            $sendinblue_source = isset( $source_data['sendinblue'] ) && is_array( $source_data['sendinblue'] )
                ? $source_data['sendinblue']
                : array();

            if ( ! empty( $sendinblue_source['api_key'] ) ) {
                $settings['brevo'] = array(
                    'api_key' => sanitize_text_field( $sendinblue_source['api_key'] ),
                );
            }
        }

        // ------------------------------------------------------------------ //
        // General settings.
        // ------------------------------------------------------------------ //
        $general_source   = isset( $source_data['general'] ) && is_array( $source_data['general'] )
            ? $source_data['general']
            : array();
        $general_settings = array();

        if ( isset( $general_source['do_not_send'] ) ) {
            $general_settings['do_not_send'] = $this->to_bool( $general_source['do_not_send'] );
        }

        if ( isset( $general_source['uninstall'] ) ) {
            $general_settings['uninstall_data'] = $this->to_bool( $general_source['uninstall'] );
        }

        $debug_events_source = isset( $source_data['debug_events'] ) && is_array( $source_data['debug_events'] )
            ? $source_data['debug_events']
            : array();

        if ( isset( $debug_events_source['retention_period'] ) ) {
            $general_settings['debug_events_retention_days'] = max( 1, (int) round( absint( $debug_events_source['retention_period'] ) / DAY_IN_SECONDS ) );
        }

        if ( ! empty( $general_settings ) ) {
            $settings['general'] = $general_settings;
        }

        // ------------------------------------------------------------------ //
        // Logs settings.
        // ------------------------------------------------------------------ //
        $logs_source = isset( $source_data['logs'] ) && is_array( $source_data['logs'] )
            ? $source_data['logs']
            : array();

        if ( isset( $logs_source['enabled'] ) ) {
            $settings['logs']['enabled'] = $this->to_bool( $logs_source['enabled'] );
        }

        // ------------------------------------------------------------------ //
        // Alert settings (email + non-email channel warnings).
        // ------------------------------------------------------------------ //
        $this->map_alert_settings( $source_data, $settings, $warnings );

        $this->guard_mailer_has_credentials( $mapped_mailer, $settings, $warnings, $skipped );

        return array(
            'settings' => $settings,
            'warnings' => $warnings,
            'skipped'  => $skipped,
        );
    }

    /**
     * Map alert settings from the source data.
     *
     * Reads `alert_email.enabled` and `alert_email.connections`, mapping the
     * first recipient to `alerts.email_to` and additional recipients to
     * `alerts.cc`. Surfaces warnings when non-email alert channels (Slack,
     * Discord, Twilio SMS, custom webhook, push, WhatsApp) are enabled, since
     * NimblyMail only supports email alerts.
     *
     * @since 1.0.0
     *
     * @param array $source_data Full raw options array from the source plugin.
     * @param array $settings    Settings array passed by reference.
     * @param array $warnings    Warnings array passed by reference.
     */
    private function map_alert_settings( array $source_data, array &$settings, array &$warnings ): void {
        $alert_email = isset( $source_data['alert_email'] ) && is_array( $source_data['alert_email'] )
            ? $source_data['alert_email']
            : array();

        if ( isset( $alert_email['enabled'] ) ) {
            $settings['alerts']['enabled'] = $this->to_bool( $alert_email['enabled'] );
        }

        $recipients = array();
        if ( isset( $alert_email['connections'] ) && is_array( $alert_email['connections'] ) ) {
            foreach ( $alert_email['connections'] as $connection ) {
                if ( ! is_array( $connection ) || empty( $connection['send_to'] ) ) {
                    continue;
                }
                $email = sanitize_text_field( $connection['send_to'] );
                if ( '' !== $email ) {
                    $recipients[] = $email;
                }
            }
        }

        if ( ! empty( $recipients ) ) {
            $settings['alerts']['email_to'] = array_shift( $recipients );

            if ( ! empty( $recipients ) ) {
                $settings['alerts']['cc'] = implode( ',', $recipients );
            }
        }

        $other_channels = array(
            'alert_slack_webhook'      => __( 'Slack', 'nimblymail-smtp' ),
            'alert_discord_webhook'    => __( 'Discord', 'nimblymail-smtp' ),
            'alert_twilio_sms'         => __( 'Twilio SMS', 'nimblymail-smtp' ),
            'alert_custom_webhook'     => __( 'custom webhook', 'nimblymail-smtp' ),
            'alert_push_notifications' => __( 'push notifications', 'nimblymail-smtp' ),
            'alert_whatsapp'           => __( 'WhatsApp', 'nimblymail-smtp' ),
        );

        foreach ( $other_channels as $key => $label ) {
            if (
                isset( $source_data[ $key ] ) &&
                is_array( $source_data[ $key ] ) &&
                ! empty( $source_data[ $key ]['enabled'] )
            ) {
                $warnings[] = array(
                    'field'   => 'alerts.' . $key,
                    'message' => sprintf(
                        /* translators: %s: alert channel label (Slack, Discord, etc.). */
                        __( 'The %s alert channel was enabled in the source plugin but is not supported by NimblyMail. Only email alerts will be active after the import.', 'nimblymail-smtp' ),
                        $label
                    ),
                );
            }
        }
    }
}
