<?php
/**
 * Mailjet Integration for Maple Carts.
 *
 * Syncs abandoned cart data to Mailjet contact properties
 * for use in Mailjet automations.
 *
 * @package MapleCarts
 */

defined( 'ABSPATH' ) || exit;

/**
 * Mailjet integration class.
 */
class Maple_Carts_Mailjet {

    /**
     * Single instance.
     *
     * @var Maple_Carts_Mailjet
     */
    private static $instance = null;

    /**
     * Mailjet API base URL.
     *
     * @var string
     */
    private $api_url = 'https://api.mailjet.com/v3/REST';

    /**
     * Contact properties to sync.
     *
     * @var array
     */
    private $contact_properties = [
        'maple_has_abandoned_cart'   => 'bool',
        'maple_cart_total'           => 'float',
        'maple_cart_currency'        => 'str',
        'maple_cart_product_count'   => 'int',
        'maple_cart_product_names'   => 'str',
        'maple_cart_categories'      => 'str',
        'maple_cart_value_level'     => 'str',
        'maple_abandonment_type'     => 'str',
        'maple_cart_recovery_url'    => 'str',
        'maple_cart_first_seen_at'   => 'datetime',
        'maple_cart_abandoned_at'    => 'datetime',
        'maple_cart_coupon_code'     => 'str',
        'maple_customer_first_name'  => 'str',
        'maple_customer_last_name'   => 'str',
        'maple_recovered_via'        => 'str',
    ];

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

    /**
     * Constructor.
     */
    private function __construct() {
        // Admin AJAX hooks - always register so settings page works.
        add_action( 'wp_ajax_maple_carts_test_mailjet', [ $this, 'ajax_test_connection' ] );
        add_action( 'wp_ajax_maple_carts_setup_mailjet_properties', [ $this, 'ajax_setup_properties' ] );

        // Only initialize sync hooks if Mailjet mode is enabled.
        if ( 'mailjet' !== Maple_Carts::get_option( 'email_mode', 'builtin' ) ) {
            return;
        }

        // Hook into cart status changes.
        add_action( 'maple_carts_cart_abandoned', [ $this, 'sync_abandoned_cart' ], 10, 2 );
        add_action( 'maple_carts_cart_recovered', [ $this, 'clear_abandoned_cart' ], 10, 2 );
        add_action( 'maple_carts_cart_converted', [ $this, 'clear_abandoned_cart' ], 10, 2 );
    }

    /**
     * Check if Mailjet is configured.
     *
     * @return bool
     */
    public function is_configured() {
        $api_key    = Maple_Carts::get_option( 'mailjet_api_key', '' );
        $secret_key = Maple_Carts::get_option( 'mailjet_secret_key', '' );

        return ! empty( $api_key ) && ! empty( $secret_key );
    }

    /**
     * Make API request to Mailjet.
     *
     * @param string $endpoint API endpoint.
     * @param string $method   HTTP method.
     * @param array  $data     Request data.
     * @return array|WP_Error
     */
    private function api_request( $endpoint, $method = 'GET', $data = [] ) {
        $api_key    = Maple_Carts::get_option( 'mailjet_api_key', '' );
        $secret_key = Maple_Carts::get_option( 'mailjet_secret_key', '' );

        if ( empty( $api_key ) || empty( $secret_key ) ) {
            return new WP_Error( 'not_configured', __( 'Mailjet API credentials not configured.', 'maple-carts' ) );
        }

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

        $args = [
            'method'  => $method,
            'headers' => [
                'Authorization' => 'Basic ' . base64_encode( $api_key . ':' . $secret_key ),
                'Content-Type'  => 'application/json',
            ],
            'timeout' => 30,
        ];

        if ( ! empty( $data ) && in_array( $method, [ 'POST', 'PUT' ], true ) ) {
            $args['body'] = wp_json_encode( $data );
        }

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

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code( $response );
        $body = wp_remote_retrieve_body( $response );
        $data = json_decode( $body, true );

        if ( $code >= 400 ) {
            $error_message = isset( $data['ErrorMessage'] ) ? $data['ErrorMessage'] : __( 'Unknown API error', 'maple-carts' );
            return new WP_Error( 'api_error', $error_message, [ 'status' => $code ] );
        }

        return $data;
    }

    /**
     * Setup contact properties in Mailjet.
     * Should be run once during initial setup.
     *
     * @return array|WP_Error
     */
    public function setup_contact_properties() {
        $results = [];

        foreach ( $this->contact_properties as $name => $type ) {
            // Check if property already exists.
            $existing = $this->api_request( '/contactmetadata/' . $name );
            
            if ( ! is_wp_error( $existing ) && isset( $existing['Data'][0] ) ) {
                $results[ $name ] = 'exists';
                continue;
            }

            // Create the property.
            $datatype = $this->get_mailjet_datatype( $type );
            $response = $this->api_request( '/contactmetadata', 'POST', [
                'Name'      => $name,
                'Datatype'  => $datatype,
                'NameSpace' => 'static',
            ] );

            if ( is_wp_error( $response ) ) {
                $results[ $name ] = 'error: ' . $response->get_error_message();
            } else {
                $results[ $name ] = 'created';
            }
        }

        return $results;
    }

    /**
     * Get Mailjet datatype from our type.
     *
     * @param string $type Our type.
     * @return string Mailjet datatype.
     */
    private function get_mailjet_datatype( $type ) {
        $map = [
            'bool'     => 'bool',
            'int'      => 'int',
            'float'    => 'float',
            'str'      => 'str',
            'datetime' => 'datetime',
        ];

        return isset( $map[ $type ] ) ? $map[ $type ] : 'str';
    }

    /**
     * Sync abandoned cart data to Mailjet.
     *
     * @param int    $cart_id Cart ID.
     * @param object $cart    Cart object.
     */
    public function sync_abandoned_cart( $cart_id, $cart ) {
        if ( empty( $cart->email ) ) {
            return;
        }

        // Parse cart contents for product names and categories.
        $cart_contents = maybe_unserialize( $cart->cart_contents );
        $product_names = [];
        $categories    = [];

        if ( is_array( $cart_contents ) ) {
            foreach ( $cart_contents as $item ) {
                $product_names[] = $item['name'] ?? 'Product';
                
                // Get product categories.
                $product_id = $item['product_id'] ?? 0;
                if ( $product_id ) {
                    $terms = get_the_terms( $product_id, 'product_cat' );
                    if ( $terms && ! is_wp_error( $terms ) ) {
                        foreach ( $terms as $term ) {
                            $categories[ $term->name ] = true; // Use as keys to dedupe.
                        }
                    }
                }
            }
        }

        // Parse billing data for name.
        $billing_data = maybe_unserialize( $cart->billing_data );
        $first_name   = $billing_data['first_name'] ?? '';
        $last_name    = $billing_data['last_name'] ?? '';

        // Calculate value level for segmentation.
        $cart_total  = (float) $cart->cart_total;
        $value_level = $this->get_cart_value_level( $cart_total );

        // Generate recovery URL with coupon and UTM source for attribution.
        $recovery_url = Maple_Carts_Tracking::instance()->generate_recovery_url( 
            $cart->session_id, 
            $cart->coupon_code ?? '' 
        );
        // Add UTM source for recovery attribution.
        $recovery_url = add_query_arg( 'utm_source', 'mailjet', $recovery_url );

        // Prepare contact data using items_count from database (no JSON parsing needed).
        $contact_data = [
            'maple_has_abandoned_cart'  => true,
            'maple_cart_total'          => $cart_total,
            'maple_cart_currency'       => $cart->currency ?? 'USD',
            'maple_cart_product_count'  => (int) ( $cart->items_count ?? 0 ),
            'maple_cart_product_names'  => implode( ', ', array_slice( $product_names, 0, 5 ) ), // Limit to 5.
            'maple_cart_categories'     => implode( ', ', array_slice( array_keys( $categories ), 0, 5 ) ), // Limit to 5.
            'maple_cart_value_level'    => $value_level,
            'maple_abandonment_type'    => $cart->abandonment_type ?? 'checkout',
            'maple_cart_recovery_url'   => $recovery_url,
            'maple_cart_first_seen_at'  => $cart->first_seen_at ?? '',
            'maple_cart_abandoned_at'   => $cart->abandoned_at ?? current_time( 'c' ),
            'maple_cart_coupon_code'    => $cart->coupon_code ?? '',
            'maple_customer_first_name' => $first_name,
            'maple_customer_last_name'  => $last_name,
            'maple_recovered_via'       => '', // Clear any previous recovery.
        ];

        $this->update_contact( $cart->email, $contact_data );
    }

    /**
     * Get cart value level for segmentation.
     *
     * @param float $total Cart total.
     * @return string Value level: low, medium, or high.
     */
    private function get_cart_value_level( $total ) {
        if ( $total < 20 ) {
            return 'low';
        } elseif ( $total < 80 ) {
            return 'medium';
        } else {
            return 'high';
        }
    }

    /**
     * Clear abandoned cart data from Mailjet contact.
     *
     * @param int    $cart_id Cart ID.
     * @param object $cart    Cart object.
     */
    public function clear_abandoned_cart( $cart_id, $cart ) {
        if ( empty( $cart->email ) ) {
            return;
        }

        // Map recovery_source to Mailjet-friendly value.
        $recovered_via = '';
        if ( 'recovered' === $cart->status && ! empty( $cart->recovery_source ) ) {
            $recovered_via = $cart->recovery_source; // mailjet, builtin_email, email_link, direct.
        } elseif ( 'converted' === $cart->status ) {
            $recovered_via = 'purchase'; // Direct purchase without abandonment.
        }

        // Clear the abandoned cart flag and data, but record recovery attribution.
        $contact_data = [
            'maple_has_abandoned_cart'  => false,
            'maple_cart_total'          => 0,
            'maple_cart_currency'       => '',
            'maple_cart_product_count'  => 0,
            'maple_cart_product_names'  => '',
            'maple_cart_categories'     => '',
            'maple_cart_value_level'    => '',
            'maple_abandonment_type'    => '',
            'maple_cart_recovery_url'   => '',
            'maple_cart_first_seen_at'  => '',
            'maple_cart_abandoned_at'   => '',
            'maple_cart_coupon_code'    => '',
            'maple_customer_first_name' => '',
            'maple_customer_last_name'  => '',
            'maple_recovered_via'       => $recovered_via,
        ];

        $this->update_contact( $cart->email, $contact_data );
    }

    /**
     * Update or create contact in Mailjet.
     *
     * @param string $email        Contact email.
     * @param array  $contact_data Contact properties.
     * @return array|WP_Error
     */
    private function update_contact( $email, $contact_data ) {
        // First, ensure contact exists.
        $contact = $this->get_or_create_contact( $email );
        
        if ( is_wp_error( $contact ) ) {
            $this->log_error( 'Failed to get/create contact: ' . $contact->get_error_message() );
            return $contact;
        }

        // Format data for Mailjet.
        $formatted_data = [];
        foreach ( $contact_data as $name => $value ) {
            $formatted_data[] = [
                'Name'  => $name,
                'Value' => $value,
            ];
        }

        // Update contact data.
        $response = $this->api_request(
            '/contactdata/' . $contact['ID'],
            'PUT',
            [ 'Data' => $formatted_data ]
        );

        if ( is_wp_error( $response ) ) {
            $this->log_error( 'Failed to update contact data: ' . $response->get_error_message() );
        }

        return $response;
    }

    /**
     * Get or create contact in Mailjet.
     *
     * @param string $email Contact email.
     * @return array|WP_Error
     */
    private function get_or_create_contact( $email ) {
        // Try to get existing contact.
        $response = $this->api_request( '/contact/' . urlencode( $email ) );

        if ( ! is_wp_error( $response ) && isset( $response['Data'][0] ) ) {
            return $response['Data'][0];
        }

        // Create new contact.
        $response = $this->api_request( '/contact', 'POST', [
            'Email' => $email,
        ] );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        if ( isset( $response['Data'][0] ) ) {
            return $response['Data'][0];
        }

        return new WP_Error( 'create_failed', __( 'Failed to create contact', 'maple-carts' ) );
    }

    /**
     * Test Mailjet connection.
     *
     * @return array|WP_Error
     */
    public function test_connection() {
        return $this->api_request( '/user' );
    }

    /**
     * AJAX handler for testing Mailjet connection.
     */
    public function ajax_test_connection() {
        check_ajax_referer( 'maple_carts_admin', 'nonce' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( 'Unauthorized' );
        }

        // Temporarily set credentials from POST for testing.
        $api_key    = isset( $_POST['api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['api_key'] ) ) : '';
        $secret_key = isset( $_POST['secret_key'] ) ? sanitize_text_field( wp_unslash( $_POST['secret_key'] ) ) : '';

        if ( empty( $api_key ) || empty( $secret_key ) ) {
            wp_send_json_error( __( 'Please enter both API Key and Secret Key.', 'maple-carts' ) );
        }

        // Make test request.
        $url = $this->api_url . '/user';
        
        $response = wp_remote_get( $url, [
            'headers' => [
                'Authorization' => 'Basic ' . base64_encode( $api_key . ':' . $secret_key ),
            ],
            'timeout' => 15,
        ] );

        if ( is_wp_error( $response ) ) {
            wp_send_json_error( $response->get_error_message() );
        }

        $code = wp_remote_retrieve_response_code( $response );
        $body = json_decode( wp_remote_retrieve_body( $response ), true );

        if ( 200 === $code && isset( $body['Data'][0] ) ) {
            $user = $body['Data'][0];
            wp_send_json_success( [
                'message' => sprintf(
                    /* translators: %s: Mailjet username */
                    __( 'Connected successfully! Account: %s', 'maple-carts' ),
                    $user['Username'] ?? $user['Email'] ?? 'Unknown'
                ),
            ] );
        } else {
            wp_send_json_error( __( 'Authentication failed. Please check your API credentials.', 'maple-carts' ) );
        }
    }

    /**
     * AJAX handler for setting up Mailjet contact properties.
     */
    public function ajax_setup_properties() {
        check_ajax_referer( 'maple_carts_admin', 'nonce' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( 'Unauthorized' );
        }

        $results = $this->setup_contact_properties();

        if ( is_wp_error( $results ) ) {
            wp_send_json_error( $results->get_error_message() );
        }

        $created = 0;
        $existed = 0;
        $errors  = 0;

        foreach ( $results as $status ) {
            if ( 'created' === $status ) {
                $created++;
            } elseif ( 'exists' === $status ) {
                $existed++;
            } else {
                $errors++;
            }
        }

        wp_send_json_success( [
            'message' => sprintf(
                /* translators: %1$d: created count, %2$d: existed count, %3$d: error count */
                __( 'Properties setup complete. Created: %1$d, Already existed: %2$d, Errors: %3$d', 'maple-carts' ),
                $created,
                $existed,
                $errors
            ),
            'details' => $results,
        ] );
    }

    /**
     * Log error for debugging.
     *
     * @param string $message Error message.
     */
    private function log_error( $message ) {
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
            error_log( 'Maple Carts Mailjet: ' . $message );
        }
    }

    /**
     * Get available contact properties for display.
     *
     * @return array
     */
    public function get_available_properties() {
        return [
            'maple_has_abandoned_cart'   => __( 'Has abandoned cart (true/false)', 'maple-carts' ),
            'maple_cart_total'           => __( 'Cart total value', 'maple-carts' ),
            'maple_cart_currency'        => __( 'Cart currency code', 'maple-carts' ),
            'maple_cart_product_count'   => __( 'Number of items in cart', 'maple-carts' ),
            'maple_cart_product_names'   => __( 'Product names (comma separated)', 'maple-carts' ),
            'maple_cart_categories'      => __( 'Product categories (comma separated)', 'maple-carts' ),
            'maple_cart_value_level'     => __( 'Cart value: low (<$20), medium ($20-80), high ($80+)', 'maple-carts' ),
            'maple_abandonment_type'     => __( 'Abandonment stage: checkout or payment', 'maple-carts' ),
            'maple_cart_recovery_url'    => __( 'Recovery URL with coupon', 'maple-carts' ),
            'maple_cart_first_seen_at'   => __( 'First seen date/time (funnel entry)', 'maple-carts' ),
            'maple_cart_abandoned_at'    => __( 'Abandonment date/time', 'maple-carts' ),
            'maple_cart_coupon_code'     => __( 'Generated coupon code', 'maple-carts' ),
            'maple_customer_first_name'  => __( 'Customer first name', 'maple-carts' ),
            'maple_customer_last_name'   => __( 'Customer last name', 'maple-carts' ),
            'maple_recovered_via'        => __( 'Recovery attribution: mailjet, builtin_email, email_link, direct, purchase', 'maple-carts' ),
        ];
    }
}
