<?php
/**
 * MailerLite API Client for MetForm Integration
 * 
 * This class handles API communication with MailerLite to fetch groups and fields
 * for form integration purposes.
 * 
 * @package MetForm
 * @version 3.9.7
 */

namespace MetForm_Pro\Core\Integrations;

class Mailerlite {

    /**
     * API Key
     * @var string
     */
    private $api_key;

    /**
     * API Base URL
     * @var string
     */
    private $base_url = 'https://connect.mailerlite.com/api';

    /**
     * Last error message
     * @var string
     */
    private $last_error = '';

    /**
     * Constructor
     * 
     * @param string $api_key MailerLite API Key
     */
    public function __construct( $api_key = '' ) {
        $this->api_key = $api_key;
    }

    /**
     * Set API Key
     * 
     * @param string $api_key
     * @return void
     */
    public function set_api_key( $api_key ) {
        $this->api_key = $api_key;
    }

    /**
     * Get API Key
     * 
     * @return string
     */
    public function get_api_key() {
        return $this->api_key;
    }

    /**
     * Make API Request
     * 
     * @param string $endpoint API endpoint
     * @param string $method HTTP method (GET, POST, PUT, DELETE)
     * @param array $data Request data
     * @return array|false Response data or false on failure
     */
    private function make_request( $endpoint, $method = 'GET', $data = array() ) {
        
        if ( empty( $this->api_key ) ) {
            $this->last_error = 'API Key is required';
            return false;
        }

        $url = $this->base_url . $endpoint;

        $args = array(
            'method'  => $method,
            'headers' => array(
                'Content-Type'  => 'application/json',
                'Accept'        => 'application/json',
                'Authorization' => 'Bearer ' . $this->api_key,
                'User-Agent'    => 'MetForm-MailerLite-Integration/1.0',
            ),
            'timeout' => 30,
            'sslverify' => true,
        );

        // Add body data for POST/PUT requests
        if ( in_array( $method, array( 'POST', 'PUT' ) ) && ! empty( $data ) ) {
            $args['body'] = json_encode( $data );
        }

        // For GET requests, add query parameters to URL
        if ( $method === 'GET' && ! empty( $data ) ) {
            $url = add_query_arg( $data, $url );
        }

        $response = wp_remote_request( $url, $args );

        // Check for errors
        if ( is_wp_error( $response ) ) {
            $this->last_error = $response->get_error_message();
            return false;
        }

        $response_code = wp_remote_retrieve_response_code( $response );
        $response_body = wp_remote_retrieve_body( $response );

        // Handle rate limiting
        if ( $response_code == 429 ) {
            $this->last_error = 'Rate limit exceeded. Please try again later.';
            return false;
        }

        // Check for successful response
        if ( $response_code < 200 || $response_code >= 300 ) {
            $error_data = json_decode( $response_body, true );
            
            if ( isset( $error_data['message'] ) ) {
                $error_message = $error_data['message'];
            } elseif ( $response_code === 403 ) {
                $error_message = 'Forbidden (403): Your API key may not have permission or may be invalid. Verify your API key in MailerLite dashboard.';
            } elseif ( $response_code === 401 ) {
                $error_message = 'Unauthorized (401): API key is invalid or missing.';
            } else {
                $error_message = 'API request failed with code ' . $response_code;
            }
            
            $this->last_error = $error_message;
            return false;
        }

        $decoded_response = json_decode( $response_body, true );

        if ( json_last_error() !== JSON_ERROR_NONE ) {
            $this->last_error = 'Failed to decode API response';
            return false;
        }

        return $decoded_response;
    }

    /**
     * Get all groups
     * 
     * @param array $args Optional arguments (limit, page, filter, sort)
     * @return array|false Array of groups or false on failure
     */
    public function get_groups( $args = array() ) {
        
        $defaults = array(
            'limit' => 100, // Max 1000
            'page'  => 1,
        );

        $params = wp_parse_args( $args, $defaults );

        $response = $this->make_request( '/groups', 'GET', $params );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : array();
    }

    /**
     * Get all groups formatted for dropdown
     * 
     * @return array Array with group_id => group_name
     */
    public function get_groups_for_dropdown() {
        $groups = $this->get_groups();
        
        if ( $groups === false ) {
            return array();
        }

        $dropdown_options = array();
        
        foreach ( $groups as $group ) {
            $dropdown_options[ $group['id'] ] = $group['name'];
        }

        return $dropdown_options;
    }

    /**
     * Get single group by ID
     * 
     * @param string|int $group_id Group ID
     * @return array|false Group data or false on failure
     */
    public function get_group( $group_id ) {
        $response = $this->make_request( "/groups/{$group_id}", 'GET' );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : false;
    }

    /**
     * Get all fields
     * 
     * @param array $args Optional arguments (limit, page, filter, sort)
     * @return array|false Array of fields or false on failure
     */
    public function get_fields( $args = array() ) {
        
        $defaults = array(
            'limit' => 100,
            'page'  => 1,
        );

        $params = wp_parse_args( $args, $defaults );

        $response = $this->make_request( '/fields', 'GET', $params );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : array();
    }

    /**
     * Get fields formatted for mapping
     * Returns array with field details for easy mapping
     * 
     * @return array Array of fields with key, name, and type
     */
    public function get_fields_for_mapping() {
        $fields = $this->get_fields();
        
        if ( $fields === false ) {
            return array();
        }

        $mapped_fields = array();
        
        foreach ( $fields as $field ) {
            $mapped_fields[] = array(
                'key'   => $field['key'],     // e.g., 'name', 'last_name', 'company'
                'name'  => $field['name'],    // e.g., 'Name', 'Last Name', 'Company'
                'type'  => $field['type'],    // e.g., 'text', 'number', 'date'
                'id'    => $field['id'],      // Field ID
            );
        }

        return $mapped_fields;
    }

    /**
     * Get subscribers from a specific group
     * 
     * @param string|int $group_id Group ID
     * @param array $args Optional arguments (filter, limit, cursor)
     * @return array|false Array of subscribers or false on failure
     */
    public function get_group_subscribers( $group_id, $args = array() ) {
        
        $defaults = array(
            'limit' => 50, // Max 1000
        );

        $params = wp_parse_args( $args, $defaults );

        $response = $this->make_request( "/groups/{$group_id}/subscribers", 'GET', $params );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : array();
    }

    /**
     * Create or update subscriber
     * 
     * @param array $subscriber_data Subscriber data including email and fields
     * @return array|false Subscriber data or false on failure
     */
    public function create_or_update_subscriber( $subscriber_data ) {
        
        if ( ! isset( $subscriber_data['email'] ) || empty( $subscriber_data['email'] ) ) {
            $this->last_error = 'Email is required';
            return false;
        }

        $response = $this->make_request( '/subscribers', 'POST', $subscriber_data );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : false;
    }

    /**
     * Assign subscriber to a group
     * 
     * @param string|int $subscriber_id Subscriber ID
     * @param string|int $group_id Group ID
     * @return array|false Response data or false on failure
     */
    public function assign_subscriber_to_group( $subscriber_id, $group_id ) {
        $response = $this->make_request( "/subscribers/{$subscriber_id}/groups/{$group_id}", 'POST' );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : false;
    }

    /**
     * Subscribe a contact to a specific group with field data
     * Creates/updates the subscriber and assigns to the group in a single API call.
     *
     * @param string $email Subscriber email address
     * @param string|int $group_id MailerLite group ID
     * @param array $fields Associative array of subscriber fields (key => value)
     * @return array|false Subscriber data or false on failure
     */
    public function subscribe_to_group( $email, $group_id, $fields = array() ) {

        if ( empty( $email ) || ! is_email( $email ) ) {
            $this->last_error = 'A valid email address is required.';
            return false;
        }

        if ( empty( $group_id ) ) {
            $this->last_error = 'A group ID is required.';
            return false;
        }

        $subscriber_data = array(
            'email'  => sanitize_email( $email ),
            'groups' => array( (string) $group_id ),
        );

        if ( ! empty( $fields ) ) {
            $subscriber_data['fields'] = $fields;
        }

        $response = $this->make_request( '/subscribers', 'POST', $subscriber_data );

        if ( $response === false ) {
            return false;
        }

        return isset( $response['data'] ) ? $response['data'] : false;
    }

    /**
     * Process a MetForm submission for MailerLite integration.
     * Uses saved field mapping to map form data to MailerLite fields,
     * then subscribes the contact to the configured group.
     *
     * @param int    $form_id   The MetForm form ID
     * @param array  $form_data The submitted form data
     * @param string $email     The subscriber's email address
     * @return array Result with 'status' (1=success, 0=fail) and optional 'message'
     */
    public function process_form_submission( $form_id, $form_data, $email ) {

        $result = array( 'status' => 0, 'message' => '' );

        // Get the saved group ID from form settings
        $group_id = get_post_meta( $form_id, 'mf_mailerlite_list_id', true );

        // Fallback: try from form settings option
        if ( empty( $group_id ) ) {
            $form_settings = \MetForm\Core\Forms\Action::instance()->get_all_data( $form_id );
            $group_id = isset( $form_settings['mf_mailerlite_list_id'] ) ? $form_settings['mf_mailerlite_list_id'] : '';
        }

        if ( empty( $group_id ) ) {
            $result['message'] = 'No MailerLite group configured for this form.';
            return $result;
        }

        // Get saved field mapping
        $field_mapping = get_option( 'mf_mailerlite_field_mapping_' . $form_id, array() );

        // Build subscriber fields from the mapping
        $subscriber_fields = array();
        $subscriber_email  = sanitize_email( $email );

        if ( ! empty( $field_mapping ) ) {
            foreach ( $field_mapping as $ml_field_key => $form_field_name ) {
                if ( empty( $form_field_name ) || ! isset( $form_data[ $form_field_name ] ) ) {
                    continue;
                }

                $value = sanitize_text_field( $form_data[ $form_field_name ] );

                // 'email' mapping — use this as the subscriber email if present
                if ( $ml_field_key === 'email' ) {
                    $subscriber_email = sanitize_email( $value );
                } else {
                    $subscriber_fields[ $ml_field_key ] = $value;
                }
            }
        }

        if ( empty( $subscriber_email ) || ! is_email( $subscriber_email ) ) {
            $result['message'] = 'Valid email is required for MailerLite subscription.';
            return $result;
        }

        // Subscribe to the group
        $response = $this->subscribe_to_group( $subscriber_email, $group_id, $subscriber_fields );

        if ( $response !== false ) {
            $result['status']  = 1;
            $result['message'] = 'Successfully subscribed to MailerLite.';
        } else {
            $result['message'] = $this->get_last_error();
        }

        return $result;
    }

    /**
     * Test API connection with detailed diagnostics
     * 
     * @return array|bool Array with detailed info or false on failure
     */
    public function test_connection_detailed() {
        $result = array(
            'success' => false,
            'api_key_format_valid' => false,
            'api_key_set' => ! empty( $this->api_key ),
            'error' => '',
            'response_code' => '',
        );

        // Check API key format
        if ( empty( $this->api_key ) ) {
            $result['error'] = 'API Key is empty';
            return $result;
        }

        $result['api_key_format_valid'] = self::validate_api_key_format( $this->api_key );

        // Try to fetch groups
        $groups = $this->get_groups( array( 'limit' => 1 ) );
        
        if ( $groups !== false ) {
            $result['success'] = true;
            $result['message'] = 'Connected successfully. Found ' . count( $groups ) . ' group(s).';
        } else {
            $result['error'] = $this->get_last_error();
        }

        return $result;
    }

    /**
     * Test API connection
     * Simple test to verify if API key is valid
     * 
     * @return bool True if connection successful, false otherwise
     */
    public function test_connection() {
        $groups = $this->get_groups( array( 'limit' => 1 ) );
        return $groups !== false;
    }

    /**
     * Get last error message
     * 
     * @return string Error message
     */
    public function get_last_error() {
        return $this->last_error;
    }

    /**
     * Clear last error
     * 
     * @return void
     */
    public function clear_last_error() {
        $this->last_error = '';
    }

    /**
     * Validate API key format
     * Basic validation to check if API key looks valid
     * 
     * @param string $api_key
     * @return bool
     */
    public static function validate_api_key_format( $api_key ) {
        // MailerLite API keys are typically long alphanumeric strings
        return ! empty( $api_key ) && strlen( $api_key ) > 20 && preg_match( '/^[a-zA-Z0-9]+$/', $api_key );
    }

    /**
     * Sanitize field mapping data
     * 
     * @param array $form_fields MetForm fields
     * @param array $mailerlite_fields MailerLite fields
     * @param array $mapping Field mapping array
     * @return array Sanitized subscriber data
     */
    public static function prepare_subscriber_data( $form_data, $field_mapping ) {
        
        $subscriber_data = array();
        $fields = array();

        foreach ( $field_mapping as $form_field => $mailerlite_field ) {
            
            if ( ! isset( $form_data[ $form_field ] ) ) {
                continue;
            }

            $value = sanitize_text_field( $form_data[ $form_field ] );

            // Email is a special field
            if ( $mailerlite_field === 'email' ) {
                $subscriber_data['email'] = sanitize_email( $value );
            } else {
                // Other fields go into the 'fields' array
                $fields[ $mailerlite_field ] = $value;
            }
        }

        if ( ! empty( $fields ) ) {
            $subscriber_data['fields'] = $fields;
        }

        return $subscriber_data;
    }
}