<?php
/**
 * GGM Commerce Email Manager
 * Main orchestrator for all email notifications
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class GGM_Commerce_Email_Manager {

    /**
     * Singleton instance
     *
     * @var GGM_Commerce_Email_Manager
     */
    private static $instance = null;

    /**
     * Registered email types
     *
     * @var array
     */
    private $emails = array();

    /**
     * Email settings
     *
     * @var array
     */
    private $settings = array();

    /**
     * Get singleton instance
     *
     * @return GGM_Commerce_Email_Manager
     */
    public static function instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor
     */
    private function __construct() {
        $this->load_settings();
        $this->load_email_classes();
        $this->register_emails();
        $this->init_hooks();
    }

    /**
     * Load email settings
     */
    private function load_settings() {
        $this->settings = get_option( 'ggm_commerce_email_options', array() );
    }

    /**
     * Load email class files
     */
    private function load_email_classes() {
        $email_dir = plugin_dir_path( __FILE__ ) . 'emails/';

        // Load base class first
        require_once plugin_dir_path( __FILE__ ) . 'class-email-template.php';

        // Load admin settings class
        require_once plugin_dir_path( __FILE__ ) . 'class-email-admin-settings.php';

        // Load subscription email base class.
        require_once plugin_dir_path( __FILE__ ) . 'class-email-subscription-template.php';

        // Load individual email classes
        $email_files = array(
            'class-email-order-confirmation.php',
            'class-email-order-shipped.php',
            'class-email-order-delivered.php',
            'class-email-order-completed.php',
            'class-email-payment-failed.php',
            'class-email-refund.php',
            'class-email-new-order-admin.php',
            'class-email-voucher.php',
            // Subscription emails.
            'class-email-subscription-activated.php',
            'class-email-subscription-renewed.php',
            'class-email-subscription-payment-failed.php',
            'class-email-subscription-paused.php',
            'class-email-subscription-resumed.php',
            'class-email-subscription-cancelled.php',
            'class-email-subscription-expired.php',
            'class-email-subscription-trial-ending.php',
            'class-email-subscription-payment-retry.php',
            'class-email-subscription-new-admin.php',
            'class-email-subscription-cancelled-admin.php',
        );

        foreach ( $email_files as $file ) {
            $filepath = $email_dir . $file;
            if ( file_exists( $filepath ) ) {
                require_once $filepath;
            }
        }

        // Initialize admin settings
        if ( is_admin() ) {
            ggm_commerce_email_admin();
        }
    }

    /**
     * Register all email types
     */
    private function register_emails() {
        $this->emails = array(
            'order_confirmation' => new GGM_Commerce_Email_Order_Confirmation(),
            'order_shipped'      => new GGM_Commerce_Email_Order_Shipped(),
            'order_delivered'    => new GGM_Commerce_Email_Order_Delivered(),
            'order_completed'    => new GGM_Commerce_Email_Order_Completed(),
            'payment_failed'     => new GGM_Commerce_Email_Payment_Failed(),
            'refund'             => new GGM_Commerce_Email_Refund(),
            'new_order_admin'    => new GGM_Commerce_Email_New_Order_Admin(),
            'voucher'            => new GGM_Commerce_Email_Voucher(),

            // Subscription emails.
            'subscription_activated'       => new GGM_Commerce_Email_Subscription_Activated(),
            'subscription_renewed'         => new GGM_Commerce_Email_Subscription_Renewed(),
            'subscription_payment_failed'  => new GGM_Commerce_Email_Subscription_Payment_Failed(),
            'subscription_paused'          => new GGM_Commerce_Email_Subscription_Paused(),
            'subscription_resumed'         => new GGM_Commerce_Email_Subscription_Resumed(),
            'subscription_cancelled'       => new GGM_Commerce_Email_Subscription_Cancelled(),
            'subscription_expired'         => new GGM_Commerce_Email_Subscription_Expired(),
            'subscription_trial_ending'    => new GGM_Commerce_Email_Subscription_Trial_Ending(),
            'subscription_payment_retry'   => new GGM_Commerce_Email_Subscription_Payment_Retry(),
            'subscription_new_admin'       => new GGM_Commerce_Email_Subscription_New_Admin(),
            'subscription_cancelled_admin' => new GGM_Commerce_Email_Subscription_Cancelled_Admin(),
        );
    }

    /**
     * Initialize WordPress hooks
     */
    private function init_hooks() {
        // Order status changes
        add_action( 'ggm_commerce_order_status_changed', array( $this, 'on_order_status_changed' ), 10, 3 );

        // Payment gateway completions (for immediate confirmation)
        add_action( 'ggm_commerce_stripe_payment_completed', array( $this, 'on_payment_completed' ), 10, 2 );
        add_action( 'ggm_commerce_paypal_payment_completed', array( $this, 'on_payment_completed' ), 10, 2 );

        // Shipment status changes
        add_action( 'ggmc_shipment_status_shipped', array( $this, 'on_shipment_shipped' ), 10, 2 );
        add_action( 'ggmc_shipment_status_delivered', array( $this, 'on_shipment_delivered' ), 10, 2 );

        // Subscription events.
        add_action( 'ggmc_subscription_activated', array( $this, 'on_subscription_activated' ) );
        add_action( 'ggmc_subscription_renewal_succeeded', array( $this, 'on_subscription_renewed' ) );
        add_action( 'ggmc_subscription_renewal_failed', array( $this, 'on_subscription_renewal_failed' ) );
        add_action( 'ggmc_subscription_paused', array( $this, 'on_subscription_paused' ) );
        add_action( 'ggmc_subscription_resumed', array( $this, 'on_subscription_resumed' ) );
        add_action( 'ggmc_subscription_cancelled', array( $this, 'on_subscription_cancelled' ) );
        add_action( 'ggmc_subscription_expired', array( $this, 'on_subscription_expired' ) );
        add_action( 'ggmc_subscription_trial_ending', array( $this, 'on_subscription_trial_ending' ), 10, 2 );
        add_action( 'ggmc_subscription_payment_retry', array( $this, 'on_subscription_payment_retry' ), 10, 2 );

        // Content type filter for HTML emails
        add_filter( 'wp_mail_content_type', array( $this, 'set_html_content_type' ) );
    }

    /**
     * Handle order status changes
     *
     * @param int    $order_id       Order ID.
     * @param string $status         New status.
     * @param string $payment_status Payment status.
     */
    public function on_order_status_changed( $order_id, $status, $payment_status ) {
        switch ( $status ) {
            case 'completed':
                $this->send( 'order_completed', $order_id );
                break;

            case 'refunded':
                $this->send( 'refund', $order_id );
                break;
        }

        // Handle payment status changes
        if ( 'failed' === $payment_status ) {
            $this->send( 'payment_failed', $order_id );
        }
    }

    /**
     * Handle successful payment completion
     *
     * @param int   $order_id Order ID.
     * @param mixed $response Payment gateway response.
     */
    public function on_payment_completed( $order_id, $response = null ) {
        // Send customer confirmation
        $this->send( 'order_confirmation', $order_id );

        // Send admin notification
        $this->send( 'new_order_admin', $order_id );
    }

    /**
     * Handle shipment shipped status
     *
     * @param int $shipment_id Shipment ID.
     * @param int $order_id    Order ID.
     */
    public function on_shipment_shipped( $shipment_id, $order_id ) {
        $this->send( 'order_shipped', $order_id, array( 'shipment_id' => $shipment_id ) );
    }

    /**
     * Handle shipment delivered status
     *
     * @param int $shipment_id Shipment ID.
     * @param int $order_id    Order ID.
     */
    public function on_shipment_delivered( $shipment_id, $order_id ) {
        $this->send( 'order_delivered', $order_id, array( 'shipment_id' => $shipment_id ) );
    }

    /**
     * Send an email
     *
     * @param string $email_type Type of email to send.
     * @param int    $order_id   Order ID.
     * @param array  $extra_args Additional arguments.
     * @return bool Whether email was sent successfully.
     */
    public function send( $email_type, $order_id, $extra_args = array() ) {
        if ( ! isset( $this->emails[ $email_type ] ) ) {
            return false;
        }

        $email = $this->emails[ $email_type ];

        // Check if email is enabled
        if ( ! $email->is_enabled() ) {
            return false;
        }

        return $email->trigger( $order_id, $extra_args );
    }

    /**
     * Get email instance by type
     *
     * @param string $type Email type.
     * @return GGM_Commerce_Email_Template|null
     */
    public function get_email( $type ) {
        return isset( $this->emails[ $type ] ) ? $this->emails[ $type ] : null;
    }

    /**
     * Get all registered email types
     *
     * @return array
     */
    public function get_email_types() {
        return $this->emails;
    }

    /**
     * Get email setting
     *
     * @param string $key     Setting key.
     * @param mixed  $default Default value.
     * @return mixed
     */
    public function get_setting( $key, $default = '' ) {
        return isset( $this->settings[ $key ] ) ? $this->settings[ $key ] : $default;
    }

    /**
     * Get from email address
     *
     * @return string
     */
    public function get_from_email() {
        $from = $this->get_setting( 'from_email' );
        return ! empty( $from ) ? $from : get_option( 'admin_email' );
    }

    /**
     * Get from name
     *
     * @return string
     */
    public function get_from_name() {
        $name = $this->get_setting( 'from_name' );
        return ! empty( $name ) ? $name : get_bloginfo( 'name' );
    }

    /**
     * Get admin email address
     *
     * @return string
     */
    public function get_admin_email() {
        $admin = $this->get_setting( 'admin_email' );
        return ! empty( $admin ) ? $admin : get_option( 'admin_email' );
    }

    /**
     * Set HTML content type for emails
     *
     * @return string
     */
    public function set_html_content_type() {
        return 'text/html';
    }

    /**
     * Send email using wp_mail
     *
     * @param string $to      Recipient email.
     * @param string $subject Email subject.
     * @param string $content Email body.
     * @param array  $headers Additional headers.
     * @return bool
     */
    public function send_email( $to, $subject, $content, $headers = array() ) {
        // Build headers
        $default_headers = array(
            'Content-Type: text/html; charset=UTF-8',
            'From: ' . $this->get_from_name() . ' <' . $this->get_from_email() . '>',
        );

        $headers = array_merge( $default_headers, $headers );

        // Capture PHPMailer errors.
        $mail_error = '';
        $error_handler = function( $wp_error ) use ( &$mail_error ) {
            $mail_error = $wp_error->get_error_message();
        };
        add_action( 'wp_mail_failed', $error_handler );

        $sent = wp_mail( $to, $subject, $content, $headers );

        remove_action( 'wp_mail_failed', $error_handler );

        if ( ! $sent ) {
            error_log( 'GGM Commerce wp_mail failed to ' . $to . ': ' . $mail_error );
        }

        return $sent;
    }

    /**
     * Log email
     *
     * @param string $email_type Type of email.
     * @param int    $order_id   Order ID.
     * @param string $recipient  Recipient email.
     * @param string $subject    Email subject.
     * @param bool   $success    Whether email was sent.
     * @param string $error      Error message if failed.
     */
    public function log_email( $email_type, $order_id, $recipient, $subject, $success = true, $error = '' ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->insert(
            "{$wpdb->prefix}ggmc_email_log",
            array(
                'email_type'    => $email_type,
                'order_id'      => $order_id,
                'recipient'     => $recipient,
                'subject'       => $subject,
                'status'        => $success ? 'sent' : 'failed',
                'error_message' => $error,
                'sent_at'       => current_time( 'mysql' ),
            ),
            array( '%s', '%d', '%s', '%s', '%s', '%s', '%s' )
        );
    }

    /**
     * Get email logs for an order
     *
     * @param int $order_id Order ID.
     * @return array
     */
    public function get_order_email_logs( $order_id ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_email_log WHERE order_id = %d ORDER BY sent_at DESC",
                $order_id
            )
        );
    }

    /**
     * Send voucher email to recipient.
     *
     * @param string $recipient    Recipient email address.
     * @param array  $voucher_data Voucher data (code, value, type, expires, product_name, order_number).
     * @param object $order        Order object.
     * @return bool Whether email was sent.
     */
    public function send_voucher_email( $recipient, $voucher_data, $order ) {
        if ( ! isset( $this->emails['voucher'] ) ) {
            return false;
        }

        $email = $this->emails['voucher'];

        // Check if email is enabled.
        if ( ! $email->is_enabled() ) {
            return false;
        }

        // Format voucher value.
        $formatted_value = '';
        if ( $voucher_data['type'] === GGM_Commerce_Discounts::TYPE_PERCENTAGE ) {
            $formatted_value = $voucher_data['value'] . '%';
        } else {
            $formatted_value = GGM_Commerce_Helpers::format_price( $voucher_data['value'] );
        }

        // Format expiry notice.
        $expiry_notice = '';
        if ( ! empty( $voucher_data['expires'] ) ) {
            $expiry_date = wp_date( get_option( 'date_format' ), strtotime( $voucher_data['expires'] ) );
            $expiry_notice = '<p style="margin: 10px 0 0 0; font-size: 14px; opacity: 0.9;">' .
                sprintf(
                    /* translators: %s: expiry date */
                    __( 'Valid until: %s', 'ggm-commerce' ),
                    $expiry_date
                ) . '</p>';
        }

        // Get email subject and content with placeholders.
        $subject = $email->get_subject();
        $content = $email->get_content();

        // Customer name from order.
        $customer_first_name = '';
        if ( ! empty( $order->billing_first_name ) ) {
            $customer_first_name = $order->billing_first_name;
        } elseif ( ! empty( $order->customer_first_name ) ) {
            $customer_first_name = $order->customer_first_name;
        } else {
            $customer_first_name = __( 'Customer', 'ggm-commerce' );
        }

        // Replace placeholders.
        $placeholders = array(
            '{voucher_code}'          => $voucher_data['code'],
            '{voucher_value}'         => $formatted_value,
            '{voucher_expiry_notice}' => $expiry_notice,
            '{product_name}'          => $voucher_data['product_name'],
            '{order_number}'          => $voucher_data['order_number'],
            '{customer_first_name}'   => $customer_first_name,
            '{business_email}'        => $this->get_from_email(),
            '{business_name}'         => $this->get_from_name(),
            '{site_url}'              => home_url(),
        );

        $subject = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $subject );
        $content = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $content );

        // Wrap in email template.
        $html_content = $email->wrap_content( $content, $email->get_heading() );
        $html_content = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $html_content );

        // Send the email.
        $sent = $this->send_email( $recipient, $subject, $html_content );

        // Log the email.
        $this->log_email( 'voucher', $order->id, $recipient, $subject, $sent );

        return $sent;
    }

    // -------------------------------------------------------------------------
    // Subscription email event handlers.
    // -------------------------------------------------------------------------

    /**
     * Send a subscription email.
     *
     * @param string $email_type      Email type key.
     * @param int    $subscription_id Subscription ID.
     * @param array  $extra_args      Extra arguments.
     * @return bool
     */
    public function send_subscription_email( $email_type, $subscription_id, $extra_args = array() ) {
        if ( ! isset( $this->emails[ $email_type ] ) ) {
            return false;
        }

        $email = $this->emails[ $email_type ];

        if ( ! $email->is_enabled() ) {
            return false;
        }

        return $email->trigger( $subscription_id, $extra_args );
    }

    /**
     * Subscription activated.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_activated( $subscription_id ) {
        $this->send_subscription_email( 'subscription_activated', $subscription_id );
        $this->send_subscription_email( 'subscription_new_admin', $subscription_id );
    }

    /**
     * Subscription renewal succeeded.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_renewed( $subscription_id ) {
        $this->send_subscription_email( 'subscription_renewed', $subscription_id );
    }

    /**
     * Subscription renewal failed.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_renewal_failed( $subscription_id ) {
        $this->send_subscription_email( 'subscription_payment_failed', $subscription_id );
    }

    /**
     * Subscription paused.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_paused( $subscription_id ) {
        $this->send_subscription_email( 'subscription_paused', $subscription_id );
    }

    /**
     * Subscription resumed.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_resumed( $subscription_id ) {
        $this->send_subscription_email( 'subscription_resumed', $subscription_id );
    }

    /**
     * Subscription cancelled.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_cancelled( $subscription_id ) {
        $sub = GGM_Commerce_Subscriptions::instance()->get_subscription( $subscription_id );
        $reason = $sub->cancellation_reason ?? '';

        $this->send_subscription_email( 'subscription_cancelled', $subscription_id );
        $this->send_subscription_email( 'subscription_cancelled_admin', $subscription_id, array( 'cancellation_reason' => $reason ) );
    }

    /**
     * Subscription expired.
     *
     * @param int $subscription_id Subscription ID.
     */
    public function on_subscription_expired( $subscription_id ) {
        $this->send_subscription_email( 'subscription_expired', $subscription_id );
    }

    /**
     * Subscription trial ending soon.
     *
     * @param int $subscription_id Subscription ID.
     * @param int $days_remaining  Days until trial ends.
     */
    public function on_subscription_trial_ending( $subscription_id, $days_remaining = 3 ) {
        $this->send_subscription_email( 'subscription_trial_ending', $subscription_id, array(
            'days_remaining' => $days_remaining,
        ) );
    }

    /**
     * Subscription payment retry scheduled.
     *
     * @param int   $subscription_id Subscription ID.
     * @param array $retry_data      Retry data (retry_number, scheduled_at).
     */
    public function on_subscription_payment_retry( $subscription_id, $retry_data = array() ) {
        $this->send_subscription_email( 'subscription_payment_retry', $subscription_id, array(
            'retry_number' => $retry_data['retry_number'] ?? 1,
            'retry_date'   => $retry_data['scheduled_at'] ?? '',
        ) );
    }
}

/**
 * Get email manager instance
 *
 * @return GGM_Commerce_Email_Manager
 */
function ggm_commerce_emails() {
    return GGM_Commerce_Email_Manager::instance();
}
