<?php
/**
 * Stablezact API Handler.
 *
 * Handles interaction with the Stablezact API.
 *
 * @class       Stablezact_API
 * @version     1.0.0
 * @package     Stablezact
 */

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

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

/**
 * Stablezact_API Class.
 */
class Stablezact_API {

    /**
     * Public key (replaces api_key + api_secret)
     *
     * @var string
     */
    private $public_key;

    /**
     * Test mode flag
     *
     * @var bool
     */
    private $testmode;

    /**
     * Debug mode flag
     *
     * @var bool
     */
    private $debug;

    /**
     * API base URL
     *
     * @var string
     */
    private $api_url;

    /**
     * Constructor.
     *
     * @param string $public_key The public key (pk_xxx format).
     * @param bool   $testmode   Whether to use testmode.
     * @param bool   $debug      Whether to enable debug mode.
     */
    public function __construct( $public_key, $testmode = false, $debug = false ) {
        $this->public_key = $public_key;
        $this->testmode   = $testmode;
        $this->debug      = $debug;

        // Set the API URL
        $this->api_url = 'https://hub.stablezact.com/api/';
    }

    /**
     * Get common headers for API requests.
     *
     * @return array
     */
    private function get_headers() {
        return array(
            'Content-Type'  => 'application/json',
            'x-public-key'  => $this->public_key,
        );
    }

    /**
     * Log API interactions if debug is enabled.
     *
     * @param string $message The log message.
     * @param string $level The log level (debug, info, error)
     * @param array  $context Additional context data
     */
    private function log($message, $level = 'debug', $context = array()) {
        // Force debug mode for credential issues
        $should_log = $this->debug || $level === 'error' || 
                      (is_array($context) && isset($context['force_log']) && $context['force_log']);

        if ($should_log) {
            if (is_array($message) || is_object($message)) {
                $message = wp_json_encode($message);
            }

            // Add basic context
            $context['public_key_set'] = !empty($this->public_key);
            $context['test_mode'] = $this->testmode;
            
            // Format the log entry
            $log_entry = sprintf(
                "[%s] [%s] %s\nContext: %s\n",
                gmdate('Y-m-d H:i:s'),
                strtoupper($level),
                $message,
                wp_json_encode($context)
            );
            
            // Log to WooCommerce logger only
            if (function_exists('wc_get_logger')) {
                $logger = wc_get_logger();
                $context['source'] = 'stablezact';

                switch ($level) {
                    case 'error':
                        $logger->error($message, $context);
                        break;
                    case 'info':
                        $logger->info($message, $context);
                        break;
                    default:
                        $logger->debug($message, $context);
                }
            }
        }
    }

    /**
     * Check if API credentials are valid
     *
     * @return bool
     */
    private function ensure_valid_credentials() {
        if (empty($this->public_key)) {
            return false;
        }

        // Validate public key format (should start with pk_)
        if (strpos($this->public_key, 'pk_') !== 0) {
            $this->log('Invalid public key format - should start with pk_', 'error');
            return false;
        }

        return true;
    }

    /**
     * Get the current public key
     *
     * @return string
     */
    public function get_public_key() {
        return $this->public_key;
    }

    /**
     * Handle API response with better error handling
     *
     * @param WP_Error|array $response The response from wp_remote_request
     * @param string $endpoint The API endpoint that was called
     * @param array $args The arguments that were passed to the request
     * @return array|WP_Error
     */
    private function handle_response($response, $endpoint = '', $args = array()) {
        if (is_wp_error($response)) {
            $this->log('API Error: ' . $response->get_error_message(), 'error', array(
                'endpoint' => $endpoint,
                'error_code' => $response->get_error_code(),
                'error_data' => $response->get_error_data(),
                'force_log' => true
            ));
            return $response;
        }

        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);
        $response_headers = wp_remote_retrieve_headers($response);
        $response_data = json_decode($response_body, true);

        $log_context = array(
            'endpoint' => $endpoint,
            'response_code' => $response_code,
            'response_headers' => $response_headers,
            'request_args' => $this->sanitize_log_data($args),
            'force_log' => true
        );

        if ($response_code >= 400) {
            $error_message = isset($response_data['error']) ? $response_data['error'] : 'Unknown API error';
            $error_code = isset($response_data['code']) ? $response_data['code'] : 'api_error';
            
            $this->log('API Error Response: ' . $error_message, 'error', array_merge($log_context, array(
                'error_code' => $error_code,
                'response_body' => $response_data
            )));
            
            if ($response_code === 401) {
                return new WP_Error('invalid_credentials', 'Invalid or expired API credentials');
            }
            
            return new WP_Error($error_code, $error_message);
        }

        $this->log('API Response: ' . $response_body, 'debug', $log_context);
        return $response_data;
    }

    /**
     * Make an API request
     *
     * @param string $endpoint API endpoint
     * @param array  $args Request arguments
     * @param string $method HTTP method
     * @param bool   $is_auth_check Whether this is an auth check request
     * @return array|WP_Error
     */
    private function request($endpoint, $args = array(), $method = 'GET', $is_auth_check = false) {
        $url = $this->api_url . $endpoint;
        
        $request_args = array(
            'method'  => $method,
            'headers' => $this->get_headers(),
            'timeout' => 45, // Increased from 30 to 45 seconds
            'redirection' => 5,
            'httpversion' => '1.1',
            'blocking' => true,
            'sslverify' => true,
            'user-agent' => 'Stablezact/' . STABLEZACT_VERSION,
        );

        if (!empty($args)) {
            if ($method === 'GET') {
                $url = add_query_arg($args, $url);
            } else {
                $request_args['body'] = json_encode($args);
            }
        }

        $this->log('API Request', 'debug', array(
            'url' => $url,
            'method' => $method,
            'args' => $this->sanitize_log_data($args),
            'is_auth_check' => $is_auth_check
        ));

        // Retry logic for DNS resolution issues
        $max_retries = 3;
        $retry_count = 0;
        
        while ($retry_count < $max_retries) {
            $response = wp_remote_request($url, $request_args);
            
            // Check if this is a DNS resolution error
            if (is_wp_error($response)) {
                $error_code = $response->get_error_code();
                $error_message = $response->get_error_message();
                
                if (strpos($error_message, 'Could not resolve host') !== false || 
                    strpos($error_message, 'resolve host') !== false ||
                    $error_code === 'http_request_failed') {
                    
                    $retry_count++;
                    $this->log('DNS Resolution Error - Retry ' . $retry_count, 'warning', array(
                        'error_code' => $error_code,
                        'error_message' => $error_message,
                        'endpoint' => $endpoint,
                        'retry_count' => $retry_count
                    ));
                    
                    if ($retry_count < $max_retries) {
                        // Wait before retrying (exponential backoff)
                        sleep(pow(2, $retry_count - 1));
                        continue;
                    }
                } else {
                    // Not a DNS error, don't retry
                    break;
                }
            } else {
                // Success, break out of retry loop
                break;
            }
        }
        
        return $this->handle_response($response, $endpoint, $args);
    }

    /**
     * Create a new payment.
     *
     * @param float  $amount         The payment amount.
     * @param string $currency       The cryptocurrency to use.
     * @param string $customer_email The customer email.
     * @param array  $metadata       Additional metadata.
     * @return array|WP_Error
     */
    public function create_payment( $amount, $currency, $customer_email, $metadata = array() ) {
        $args = array(
            'amount'         => $amount,
            'currency'       => $currency,
            'customerEmail'  => $customer_email,
            'callbackUrl'    => home_url( '/wc-api/stablezact' ),
            'metadata'       => $metadata,
        );

        return $this->request( 'payments/create', $args, 'POST' );
    }

    /**
     * Get payment details.
     *
     * @param string $payment_id The payment ID.
     * @return array|WP_Error
     */
    public function get_payment( $payment_id ) {
        return $this->request( 'payments/' . $payment_id );
    }

    /**
     * Process a payment.
     *
     * @param string $payment_id       The payment ID.
     * @param string $transaction_hash The blockchain transaction hash.
     * @param string $network          The blockchain network.
     * @return array|WP_Error
     */
    public function process_payment( $payment_id, $transaction_hash, $network = null ) {
        $args = array(
            'paymentId'       => $payment_id,
            'transactionHash' => $transaction_hash,
        );

        if ( $network ) {
            $args['network'] = $network;
        }

        return $this->request( 'payments/process', $args, 'POST' );
    }

    /**
     * Refund a payment.
     *
     * @param string $payment_id The payment ID.
     * @param array  $args       Additional arguments.
     * @return array|WP_Error
     */
    public function refund_payment( $payment_id, $args = array() ) {
        $args['paymentId'] = $payment_id;
        
        return $this->request( 'payments/refund', $args, 'POST' );
    }

    /**
     * Get merchant payment list.
     *
     * @param array $args Query arguments.
     * @return array|WP_Error
     */
    public function get_payment_list( $args = array() ) {
        $response = $this->request( 'payments', $args );
        if (is_wp_error($response)) {
            return $response;
        }
        // Return the full response for pagination info
        return $response;
    }

    /**
     * Get merchant payment stats.
     *
     * @return array|WP_Error
     */
    public function get_payment_stats() {
        $response = $this->request('payments/stats');
        if (is_wp_error($response)) {
            return $response;
        }
        // Return stats in expected format
        return $response['stats'] ?? $response;
    }

    /**
     * Verify webhook signature.
     *
     * @param string $payload        The raw webhook payload.
     * @param string $signature      The webhook signature.
     * @param string $webhook_secret The webhook secret from settings.
     * @return bool
     */
    public function verify_webhook_signature( $payload, $signature, $webhook_secret = '' ) {
        if ( empty( $webhook_secret ) || empty( $signature ) ) {
            return false;
        }

        $expected_signature = hash_hmac( 'sha256', $payload, $webhook_secret );

        return hash_equals( $expected_signature, $signature );
    }

    /**
     * Login merchant and get access token
     *
     * @param string $email Merchant email
     * @param string $password Merchant password
     * @return array|WP_Error
     */
    public function login_merchant($email, $password) {
        $args = array(
            'email' => $email,
            'password' => $password,
        );

        $response = $this->request('merchants/login', $args, 'POST');

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

        // Check if we have the merchant data in the response
        if (!isset($response['merchant']) || !isset($response['merchant']['publicKey'])) {
            return new WP_Error('invalid_response', 'Invalid login response format - publicKey not found');
        }

        // Update the instance credentials
        $this->public_key = $response['merchant']['publicKey'];

        // Return the full response for additional processing
        return array(
            'publicKey' => $response['merchant']['publicKey'],
            'merchantId' => $response['merchant']['id'],
            'status' => $response['merchant']['status']
        );
    }

    /**
     * Get merchant dashboard data
     *
     * @param array $args Query arguments (page, limit, search, status, currency, startDate, endDate)
     * @return array|WP_Error
     */
    public function get_merchant_dashboard( $args = array() ) {
        return $this->request( 'merchants/dashboard', $args );
    }

    /**
     * Get merchant fee settings
     *
     * @return array|WP_Error
     */
    public function get_merchant_fee_settings() {
        $response = $this->request('merchants/fee-settings');
        
        if (is_wp_error($response)) {
            return $response;
        }

        if (!isset($response['success']) || !isset($response['feeSettings'])) {
            return new WP_Error('invalid_response', 'Invalid fee settings response format');
        }

        return array(
            'success' => true,
            'feeSettings' => array(
                'feePercentage' => $response['feeSettings']['feePercentage'] ?? 0,
                'feeChargedTo' => $response['feeSettings']['feeChargedTo'] ?? 'customer'
            )
        );
    }

    /**
     * Update merchant profile
     *
     * @param array $profile_data Profile data to update
     * @return array|WP_Error
     */
    public function update_merchant_profile( $profile_data ) {
        return $this->request( 'merchants/profile', $profile_data, 'PUT' );
    }

    /**
     * Get merchant wallets
     *
     * @return array|WP_Error
     */
    public function get_merchant_wallets() {
        $this->log('Fetching merchant wallets');
        
        try {
            $response = $this->make_request('GET', '/merchants/wallets');
            
            if (is_wp_error($response)) {
                $this->log('Failed to fetch wallets: ' . $response->get_error_message());
                return $response;
            }
            
            $this->log('Wallet fetch response: ' . json_encode($response));
            
            // Validate response structure
            if (!isset($response['success']) || $response['success'] !== true) {
                return new WP_Error(
                    'wallet_fetch_failed',
                    $response['message'] ?? __('Failed to fetch wallet addresses', 'stablezact-crypto-payments')
                );
            }
            
            return $response;
            
        } catch (Exception $e) {
            $this->log('Exception fetching wallets: ' . $e->getMessage());
            return new WP_Error('api_exception', $e->getMessage());
        }
    }

    /**
     * Update merchant wallet addresses
     *
     * @param array $wallets Array of wallet addresses keyed by network
     * @return array|WP_Error
     */
    public function update_merchant_wallets($wallets_data) {
        // Handle both new format (array with 'wallets' key) and legacy format
        if (isset($wallets_data['wallets'])) {
            $payload = $wallets_data;
        } else {
            // Convert legacy format to new format
            $wallets = array();
            
            foreach ($wallets_data as $network => $address) {
                if (!empty($address)) {
                    // Determine supported tokens based on network
                    $supported_tokens = array();
                    switch ($network) {
                        case 'ethereum':
                            $supported_tokens = ['USDT', 'USDC', 'DAI'];
                            break;
                        case 'bsc':
                        case 'tron':
                        case 'algorand':
                        case 'solana':
                            $supported_tokens = ['USDT', 'USDC'];
                            break;
                    }
                    
                    $wallets[] = array(
                        'networkShortName' => $network,
                        'walletAddress' => $address,
                        'supportedTokens' => $supported_tokens
                    );
                }
            }
            
            $payload = array('wallets' => $wallets);
        }
        
        $this->log('Updating merchant wallets with payload: ' . json_encode($payload));
        
        try {
            $response = $this->make_request('PUT', '/merchants/wallets', $payload);
            
            if (is_wp_error($response)) {
                $this->log('Wallet update failed: ' . $response->get_error_message());
                return $response;
            }
            
            $this->log('Wallet update response: ' . json_encode($response));
            
            // Validate response structure
            if (!isset($response['success']) || $response['success'] !== true) {
                return new WP_Error(
                    'wallet_update_failed',
                    $response['message'] ?? __('Failed to update wallet addresses', 'stablezact-crypto-payments')
                );
            }
            
            return $response;
            
        } catch (Exception $e) {
            $this->log('Exception updating wallets: ' . $e->getMessage());
            return new WP_Error('api_exception', $e->getMessage());
        }
    }

    /**
     * Get merchant networks and tokens
     *
     * @return array|WP_Error
     */
    public function get_merchant_networks_and_tokens() {
        return $this->request( 'merchants/networks-and-tokens' );
    }

    /**
     * Get merchant payment list with pagination
     *
     * @param array $args Query arguments (page, limit, search, status, currency, startDate, endDate)
     * @return array|WP_Error
     */
    public function get_merchant_payments( $args = array() ) {
        return $this->request( 'payments/merchant/list', $args );
    }

    /**
     * Get merchant payment statistics
     *
     * @return array|WP_Error
     */
    public function get_merchant_payment_stats() {
        return $this->request( 'payments/merchant/stats' );
    }

    /**
     * Get admin dashboard data with comprehensive statistics
     *
     * @return array|WP_Error
     */
    public function get_admin_dashboard() {
        return $this->request( 'admin/dashboard' );
    }

    /**
     * Get all networks
     *
     * @return array|WP_Error
     */
    public function get_networks() {
        return $this->request( 'networks' );
    }

    /**
     * Get tokens for a specific network
     *
     * @param string $network_id Network ID
     * @return array|WP_Error
     */
    public function get_network_tokens( $network_id ) {
        return $this->request( 'networks/' . $network_id . '/tokens' );
    }

    /**
     * Get all stablecoins across networks
     *
     * @return array|WP_Error
     */
    public function get_stablecoins() {
        return $this->request( 'networks/stablecoins' );
    }

    /**
     * Enhanced create payment with network parameter
     *
     * @param float  $amount         The payment amount.
     * @param string $currency       The cryptocurrency to use.
     * @param string $network        The blockchain network to use.
     * @param string $customer_email The customer email.
     * @param array  $metadata       Additional metadata.
     * @return array|WP_Error
     */
    public function create_payment_enhanced( $amount, $currency, $network, $customer_email, $metadata = array() ) {
        $args = array(
            'amount'         => $amount,
            'currency'       => $currency,
            'network'        => $network,
            'customerEmail'  => $customer_email,
            'callbackUrl'    => home_url( '/wc-api/stablezact' ),
            'metadata'       => $metadata,
        );

        return $this->request( 'payments/create', $args, 'POST' );
    }

    /**
     * Enhanced process payment with sender address
     *
     * @param string $payment_id       The payment ID.
     * @param string $transaction_hash The blockchain transaction hash.
     * @param string $network          The blockchain network.
     * @param string $sender_address   The sender wallet address.
     * @return array|WP_Error
     */
    public function process_payment_enhanced( $payment_id, $transaction_hash, $network = null, $sender_address = null ) {
        $args = array(
            'paymentId'       => $payment_id,
            'transactionHash' => $transaction_hash,
        );

        if ( $network ) {
            $args['network'] = $network;
        }

        if ( $sender_address ) {
            $args['senderAddress'] = $sender_address;
        }

        return $this->request( 'payments/process', $args, 'POST' );
    }

    /**
     * Register merchant account
     *
     * @param array $merchant_data Merchant registration data
     * @return array|WP_Error
     */
    public function register_merchant( $merchant_data ) {
        return $this->request( 'merchants/register', $merchant_data, 'POST' );
    }

    /**
     * Verify merchant email
     *
     * @param string $token Verification token
     * @return array|WP_Error
     */
    public function verify_merchant_email( $token ) {
        return $this->request( 'merchants/verify-email?token=' . $token );
    }

    /**
     * Resend verification email
     *
     * @param string $email Merchant email
     * @return array|WP_Error
     */
    public function resend_verification_email( $email ) {
        $args = array( 'email' => $email );
        return $this->request( 'merchants/resend-verification', $args, 'POST' );
    }

    /**
     * Forgot password
     *
     * @param string $email Merchant email
     * @return array|WP_Error
     */
    public function forgot_password( $email ) {
        $args = array( 'email' => $email );
        return $this->request( 'merchants/forgot-password', $args, 'POST' );
    }

    /**
     * Verify OTP for password reset
     *
     * @param string $otp OTP code
     * @param string $reset_token Reset token
     * @return array|WP_Error
     */
    public function verify_otp( $otp, $reset_token ) {
        $args = array( 'otp' => $otp );
        
        $request_args = array(
            'method'    => 'POST',
            'headers'   => array_merge(
                $this->get_headers(),
                array( 'x-reset-token' => $reset_token )
            ),
            'body'      => wp_json_encode( $args ),
            'timeout'   => 60, // Increased timeout to 60 seconds
        );

        $url = $this->api_url . 'merchants/verify-otp';
        $response = wp_remote_request( $url, $request_args );
        
        return $this->handle_response( $response );
    }

    /**
     * Reset password
     *
     * @param string $new_password New password
     * @param string $reset_token Reset token
     * @return array|WP_Error
     */
    public function reset_password( $new_password, $reset_token ) {
        $args = array( 'newPassword' => $new_password );
        
        $request_args = array(
            'method'    => 'POST',
            'headers'   => array_merge(
                $this->get_headers(),
                array( 'x-reset-token' => $reset_token )
            ),
            'body'      => wp_json_encode( $args ),
            'timeout'   => 60, // Increased timeout to 60 seconds
        );

        $url = $this->api_url . 'merchants/reset-password';
        $response = wp_remote_request( $url, $request_args );
        
        return $this->handle_response( $response );
    }

    /**
     * Make authenticated requests with Bearer token
     *
     * @param string $endpoint API endpoint
     * @param array  $args Request arguments
     * @param string $method HTTP method
     * @param string $token Bearer token
     * @return array|WP_Error
     */
    public function authenticated_request( $endpoint, $args = array(), $method = 'GET', $token = '' ) {
        $url = $this->api_url . ltrim( $endpoint, '/' );
        
        $headers = $this->get_headers();
        if ( $token ) {
            $headers['Authorization'] = 'Bearer ' . $token;
        }
        
        $request_args = array(
            'method'    => $method,
            'headers'   => $headers,
            'timeout'   => 60, // Increased timeout to 60 seconds
        );

        if ( 'GET' === $method ) {
            $url = add_query_arg( $args, $url );
        } else {
            $request_args['body'] = wp_json_encode( $args );
        }

        $this->log( 'Authenticated API Request: ' . $url . ' - Method: ' . $method . ' - Args: ' . wp_json_encode( $args ) );
        
        $response = wp_remote_request( $url, $request_args );
        
        return $this->handle_response( $response );
    }

    /**
     * Public method to make generic API requests
     *
     * @param string $method HTTP method (GET, POST, etc.)
     * @param string $endpoint API endpoint
     * @param array $args Request arguments
     * @return array|WP_Error
     */
    public function make_request($method, $endpoint, $args = array()) {
        // Remove leading slash and api prefix if present
        $endpoint = ltrim($endpoint, '/');
        if (strpos($endpoint, 'api/') === 0) {
            $endpoint = substr($endpoint, 4);
        }
        
        return $this->request($endpoint, $args, $method);
    }

    /**
     * Get comprehensive merchant data including payments and wallets
     *
     * @return array|WP_Error
     */
    public function get_comprehensive_merchant_data() {
        $dashboard_data = $this->get_merchant_dashboard();
        
        if ( is_wp_error( $dashboard_data ) ) {
            return $dashboard_data;
        }
        
        // Also fetch networks and tokens
        $networks_tokens = $this->get_merchant_networks_and_tokens();
        
        if ( ! is_wp_error( $networks_tokens ) ) {
            $dashboard_data['networks'] = $networks_tokens['networks'] ?? array();
            $dashboard_data['tokens'] = $networks_tokens['tokens'] ?? array();
            $dashboard_data['merchantWallets'] = $networks_tokens['merchantWallets'] ?? array();
        }
        
        return $dashboard_data;
    }

    /**
     * Sanitize sensitive data for logging
     *
     * @param array $data Data to sanitize
     * @return array Sanitized data
     */
    private function sanitize_log_data($data) {
        $sensitive_fields = array('password', 'apiSecret', 'api_secret', 'secret', 'token');
        
        if (!is_array($data)) {
            return $data;
        }
        
        foreach ($data as $key => $value) {
            if (in_array(strtolower($key), array_map('strtolower', $sensitive_fields))) {
                $data[$key] = '***REDACTED***';
            } else if (is_array($value)) {
                $data[$key] = $this->sanitize_log_data($value);
            }
        }
        
        return $data;
    }
} 