<?php
/**
 * Handle WPForms submissions and trigger Mailjet actions.
 *
 * @package    WPFMJ
 * @subpackage WPFMJ/includes
 */

class WPFMJ_Form_Handler {

    /**
     * Maximum retry attempts (configurable via filter).
     */
    private $max_retries;

    /**
     * Constructor.
     */
    public function __construct() {
        // Allow filtering of max retry attempts (default 3, min 1, max 5)
        $this->max_retries = apply_filters('wpfmj_max_retry_attempts', 3);
        $this->max_retries = max(1, min(5, absint($this->max_retries)));
    }

    /**
     * Handle form submission.
     */
    public function handle_submission($fields, $entry, $form_data, $entry_id) {
        $form_id = $form_data['id'];

        // Find all active automations for this form
        $automations = $this->get_active_automations($form_id);

        if (empty($automations)) {
            return;
        }

        foreach ($automations as $automation) {
            $this->process_automation($automation, $fields, $entry_id);
        }
    }

    /**
     * Get active automations for a form.
     */
    private function get_active_automations($form_id) {
        $args = array(
            'post_type' => 'wpfmj_automation',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => '_wpfmj_form_id',
                    'value' => $form_id,
                    'compare' => '='
                )
            )
        );

        return get_posts($args);
    }

    /**
     * Process a single automation.
     */
    private function process_automation($automation, $fields, $entry_id) {
        $automation_id = $automation->ID;

        // Get automation settings
        $config = get_post_meta($automation_id, '_wpfmj_config', true);

        if (empty($config)) {
            $this->log_error($automation_id, $entry_id, 'missing_config', 'Automation configuration is empty');
            return;
        }

        // Validate config structure for data integrity
        $required_keys = array('field_mapping', 'trigger_field_id', 'api_key', 'api_secret', 'list_mappings');
        foreach ($required_keys as $key) {
            if (!isset($config[$key])) {
                $this->log_error($automation_id, $entry_id, 'invalid_config', "Missing required config key: {$key}");
                return;
            }
        }

        if (!isset($config['field_mapping']['email'])) {
            $this->log_error($automation_id, $entry_id, 'invalid_config', 'Email field mapping is missing');
            return;
        }

        if (!is_array($config['list_mappings']) || empty($config['list_mappings'])) {
            $this->log_error($automation_id, $entry_id, 'invalid_config', 'List mappings are empty or invalid');
            return;
        }

        // Extract form data
        $email = $this->get_field_value($fields, $config['field_mapping']['email']);
        $firstname = $this->get_field_value($fields, $config['field_mapping']['firstname']);
        $lastname = $this->get_field_value($fields, $config['field_mapping']['lastname']);
        $trigger_value = $this->get_field_value($fields, $config['trigger_field_id']);

        // Validate email address
        if (empty($email)) {
            $this->log_error($automation_id, $entry_id, 'missing_email', 'Email field is empty');
            return;
        }

        // Sanitize and validate email format
        $email = sanitize_email($email);
        if (!is_email($email)) {
            $this->log_error($automation_id, $entry_id, 'invalid_email', 'Email address is not valid: ' . sanitize_text_field($email));
            return;
        }

        // Determine which lists to add the contact to based on trigger value
        $lists_to_add = $this->get_lists_for_trigger_value($trigger_value, $config['list_mappings']);

        if (empty($lists_to_add)) {
            // No matching lists, this is normal behavior
            return;
        }

        // Prepare contact properties
        $properties = array();
        if (!empty($firstname)) {
            $properties['firstname'] = $firstname;
        }
        if (!empty($lastname)) {
            $properties['lastname'] = $lastname;
        }

        // Add to Mailjet with retry logic
        $this->add_to_mailjet_with_retry($automation_id, $entry_id, $email, $lists_to_add, $properties, $config['api_key'], $config['api_secret']);
    }

    /**
     * Get field value from fields array.
     */
    private function get_field_value($fields, $field_id) {
        if (!isset($fields[$field_id])) {
            return '';
        }

        $value = $fields[$field_id]['value'];

        // Handle arrays (checkboxes, multi-select)
        if (is_array($value)) {
            return $value;
        }

        return sanitize_text_field($value);
    }

    /**
     * Get lists for trigger value.
     */
    private function get_lists_for_trigger_value($trigger_value, $mappings) {
        $lists = array();

        // Handle array values (checkboxes, multi-select)
        if (is_array($trigger_value)) {
            foreach ($trigger_value as $value) {
                if (isset($mappings[$value])) {
                    $lists[] = $mappings[$value];
                }
            }
        } else {
            // Single value (radio, dropdown)
            if (isset($mappings[$trigger_value])) {
                $lists[] = $mappings[$trigger_value];
            }
        }

        return array_unique(array_filter($lists));
    }

    /**
     * Add to Mailjet with retry logic.
     */
    private function add_to_mailjet_with_retry($automation_id, $entry_id, $email, $lists, $properties, $api_key, $api_secret) {
        $decrypted_key = WPFMJ_Encryption::decrypt($api_key);
        $decrypted_secret = WPFMJ_Encryption::decrypt($api_secret);

        // Check for decryption failures (can happen if encryption key changed)
        if ($decrypted_key === false || $decrypted_secret === false || empty($decrypted_key) || empty($decrypted_secret)) {
            $this->log_error(
                $automation_id,
                $entry_id,
                'decryption_failed',
                'Failed to decrypt API credentials. The encryption key may have changed. Please re-save this automation with valid API credentials.'
            );
            $this->notify_admin_of_failure($automation_id, $entry_id, 'API credential decryption failed');
            return;
        }

        $api = new WPFMJ_Mailjet_API($decrypted_key, $decrypted_secret);
        
        $attempt = 0;
        $success = false;

        while ($attempt < $this->max_retries && !$success) {
            $result = $api->add_contact_to_lists($email, $lists, $properties);

            if (!is_wp_error($result)) {
                $success = true;
                
                // Log success
                do_action('wpfmj_automation_success', $automation_id, $entry_id, $email, $lists);
            } else {
                $attempt++;
                
                if ($attempt < $this->max_retries) {
                    // Exponential backoff: 1s, 2s, 4s
                    sleep(pow(2, $attempt - 1));
                } else {
                    // Max retries reached, log error
                    $this->log_error(
                        $automation_id,
                        $entry_id,
                        'mailjet_api_error',
                        $result->get_error_message(),
                        $attempt
                    );

                    // Notify admin
                    $this->notify_admin_of_failure($automation_id, $entry_id, $result->get_error_message());
                }
            }
        }
    }

    /**
     * Log error.
     */
    private function log_error($automation_id, $entry_id, $error_type, $error_message, $retry_count = 0) {
        $logger = new WPFMJ_Error_Logger();
        $logger->log($automation_id, $entry_id, $error_type, $error_message, $retry_count);
    }

    /**
     * Notify admin of failure.
     */
    private function notify_admin_of_failure($automation_id, $entry_id, $error_message) {
        // Check if notifications are disabled
        if (apply_filters('wpfmj_disable_failure_notifications', false)) {
            return;
        }

        // Get notification recipients (filterable)
        $default_email = get_option('admin_email');
        $recipients = apply_filters('wpfmj_failure_notification_emails', array($default_email));
        
        // Ensure recipients is an array
        if (!is_array($recipients)) {
            $recipients = array($default_email);
        }
        
        // Remove invalid emails
        $recipients = array_filter($recipients, function($email) {
            return is_email($email);
        });
        
        if (empty($recipients)) {
            error_log('WPFMJ: No valid email recipients for failure notification');
            return;
        }
        
        $automation_title = get_the_title($automation_id);
        $site_name = get_bloginfo('name');
        
        // Sanitize all data for email
        $automation_title = sanitize_text_field($automation_title);
        $site_name = sanitize_text_field($site_name);
        $error_message = sanitize_textarea_field($error_message);
        $entry_id = intval($entry_id);
        
        $subject = sprintf(
            '[%s] Mailjet Automation Failed',
            $site_name
        );

        $message = sprintf(
            "A Mailjet automation has failed after %d retry attempts.\n\nAutomation: %s\nEntry ID: %d\nError: %s\n\nPlease check the error logs in your WordPress admin.",
            $this->max_retries,
            $automation_title,
            $entry_id,
            $error_message
        );

        // Use wp_mail with proper headers
        $headers = array('Content-Type: text/plain; charset=UTF-8');
        
        // Send to all recipients
        foreach ($recipients as $recipient) {
            $sent = wp_mail($recipient, $subject, $message, $headers);
            
            if (!$sent) {
                error_log("WPFMJ: Failed to send notification email to {$recipient}");
            }
        }
    }
}
