<?php
/**
 * PayStarSea API Client
 * 
 * Handles all communication with PayStarSea platform API
 * Includes request signing and response signature verification
 */

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

class SeaXPay_API_Client {
    
    private $api_key;
    private $api_secret;
    private $api_url;
    
    public function __construct($api_key = null, $api_secret = null) {
        $config = seaxpay_get_config();
        
        $this->api_key = $api_key ?: ($config->api_key ?? '');
        $this->api_secret = $api_secret ?: ($config->api_secret ?? '');
        $this->api_url = rtrim(SEAXPAY_API_URL, '/');
    }
    
    public function get_platform_wallet_address($coin, $network) {
        $params = array(
            'coin' => $coin,
            'network' => $network
        );
        
        return $this->request('GET', '/api/v1/merchant/wallet/address', $params);
    }
    
    public function create_order($merchant_order_no, $fiat_amount, $fiat_currency, $coin, $network, $notify_url, $return_url) {
        $params = array(
            'merchantOrderNo' => $merchant_order_no,
            'fiatAmount' => floatval($fiat_amount),
            'fiatCurrency' => $fiat_currency,
            'coin' => $coin,
            'network' => $network,
            'notifyUrl' => $notify_url,
            'returnUrl' => $return_url
        );
        
        return $this->request('POST', '/api/v1/order/create', $params);
    }
    
    public function get_order_status($platform_order_no) {
        return $this->request('GET', '/api/v1/order/status/' . $platform_order_no);
    }
    
    public function get_supported_coins($merchant_no = null) {
        $params = array();
        if ($merchant_no !== null) {
            $params['merchantNo'] = $merchant_no;
        }
        return $this->request('GET', '/api/v1/config/coins', $params);
    }
    
    public function get_quote($fiat_amount, $fiat_currency, $coin, $network) {
        $params = array(
            'fiatAmount' => $fiat_amount,
            'fiatCurrency' => $fiat_currency,
            'coin' => $coin,
            'network' => $network
        );
        
        return $this->request('GET', '/api/v1/config/quote', $params);
    }
    
    private function request($method, $path, $params = array()) {
        $timestamp = time() * 1000;

        $sign_uri = $path;
        $url = $this->api_url . $path;
        if ($method === 'GET' && !empty($params)) {
            $canon_params = $params;
            ksort($canon_params);
            $canon_query = http_build_query($canon_params, '', '&', PHP_QUERY_RFC3986);
            $url = $this->api_url . $path . '?' . $canon_query;
            $sign_uri = $path . '?' . $canon_query;
        }

        $body_string = '';
        $has_body_method = in_array(strtoupper($method), array('POST', 'PUT', 'PATCH'), true);
        if ($has_body_method && !empty($params)) {
            $body_string = json_encode($params);
            if ($body_string === false) {
                throw new Exception(esc_html__('Failed to encode request body to JSON', 'paystarsea-crypto-payment-gateway'));
            }
        }

        $signature = $this->generate_request_signature($method, $sign_uri, $timestamp, $body_string);

        $headers = array(
            'X-Api-Key' => $this->api_key,
            'X-Timestamp' => $timestamp,
            'X-Signature' => $signature,
            'Content-Type' => 'application/json'
        );

        $args = array(
            'method' => $method,
            'headers' => $headers,
            'timeout' => 30,
            'sslverify' => true
        );

        if ($has_body_method && $body_string !== '') {
            $args['body'] = $body_string;
        }
        
        seaxpay_log('api', "API Request: $method $path", null, null, 
            seaxpay_sanitize_for_log($params), null);
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            $error_message = $response->get_error_message();
            seaxpay_log('error', "API Request Failed: $error_message", null, null, null, null);
            /* translators: %s: error message from API request */
            throw new Exception(esc_html(sprintf(__('API request failed: %s', 'paystarsea-crypto-payment-gateway'), $error_message)));
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        
        if ($status_code !== 200) {
            seaxpay_log('error', "API returned status code: $status_code", null, null, null, $body);
            /* translators: %s: HTTP status code */
            throw new Exception(esc_html(sprintf(__('API returned error status: %s', 'paystarsea-crypto-payment-gateway'), $status_code)));
        }
        
        
        $data = json_decode($body, true, 512, JSON_BIGINT_AS_STRING);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            seaxpay_log('error', 'Invalid JSON response from API', null, null, null, $body);
            throw new Exception(esc_html__('Invalid JSON response from API', 'paystarsea-crypto-payment-gateway'));
        }
        
        if (isset($data['data']['cryptoAmount'])) {
            if (preg_match('/"cryptoAmount"\s*:\s*([0-9.]+)/', $body, $matches)) {
                $data['data']['cryptoAmount'] = $matches[1];
            }
        }
        
        if (isset($data['data']['exchangeRate'])) {
            if (preg_match('/"exchangeRate"\s*:\s*([0-9.]+)/', $body, $matches)) {
                $data['data']['exchangeRate'] = $matches[1];
            }
        }
        
        if (isset($data['data']['receivedAmount'])) {
            if (preg_match('/"receivedAmount"\s*:\s*([0-9.]+)/', $body, $matches)) {
                $data['data']['receivedAmount'] = $matches[1];
            }
        }
        
        if (isset($data['data']['remainingAmount'])) {
            if (preg_match('/"remainingAmount"\s*:\s*([0-9.]+)/', $body, $matches)) {
                $data['data']['remainingAmount'] = $matches[1];
            }
        }
        
        if (!isset($data['code']) || $data['code'] !== 0) {
            $error_msg = $data['msg'] ?? 'Unknown error';
            seaxpay_log('error', "API Error: $error_msg", null, null, null, 
                seaxpay_sanitize_for_log($data));
            /* translators: %s: error message from API */
            throw new Exception(esc_html(sprintf(__('API Error: %s', 'paystarsea-crypto-payment-gateway'), $error_msg)));
        }
        
        if (!isset($data['signature']) || empty($data['signature'])) {
            seaxpay_log('error', 'Response missing signature field (possible MITM)', null, null, null, null);
            throw new Exception(esc_html__('Response signature missing, refuse to trust payload', 'paystarsea-crypto-payment-gateway'));
        }
        if (!$this->verify_response_signature_from_body($body, $data['signature'])) {
            seaxpay_log('error', 'Response signature verification failed', null, null, null, null);
            throw new Exception(esc_html__('Response signature verification failed', 'paystarsea-crypto-payment-gateway'));
        }
        
        seaxpay_log('api', "API Response Success: $method $path", null, null, null, 
            seaxpay_sanitize_for_log($data));
        
        return $data['data'] ?? array();
    }
    
    private function generate_request_signature($method, $uri, $timestamp, $body_string = '') {
        $body_hash = hash('sha256', is_string($body_string) ? $body_string : '');

        $params = array(
            'timestamp' => $timestamp,
            'method'    => $method,
            'uri'       => $uri,
            'bodyHash'  => $body_hash,
        );

        ksort($params);

        $sign_string = '';
        foreach ($params as $key => $value) {
            if ($value !== null && $value !== '') {
                if ($sign_string !== '') {
                    $sign_string .= '&';
                }
                $sign_string .= $key . '=' . $value;
            }
        }

        return hash_hmac('sha256', $sign_string, $this->api_secret);
    }
    
    private function verify_response_signature_from_body($body, $signature) {
        $data_start = strpos($body, '"data":');
        if ($data_start === false) {
            return false;
        }
        
        $data_start += 7;
        
        while ($data_start < strlen($body) && $body[$data_start] === ' ') {
            $data_start++;
        }
        
        $data_json = $this->extract_json_object($body, $data_start);
        
        if ($data_json === null) {
            return false;
        }
        
        $calculated_signature = hash_hmac('sha256', $data_json, $this->api_secret);
        
        return hash_equals($signature, $calculated_signature);
    }
    
    private function extract_json_object($str, $start) {
        if ($start >= strlen($str)) {
            return null;
        }
        
        $char = $str[$start];
        
        if ($char === '{') {
            $depth = 0;
            $in_string = false;
            $escape = false;
            
            for ($i = $start; $i < strlen($str); $i++) {
                $c = $str[$i];
                
                if ($escape) {
                    $escape = false;
                    continue;
                }
                
                if ($c === '\\' && $in_string) {
                    $escape = true;
                    continue;
                }
                
                if ($c === '"' && !$escape) {
                    $in_string = !$in_string;
                    continue;
                }
                
                if (!$in_string) {
                    if ($c === '{') {
                        $depth++;
                    } else if ($c === '}') {
                        $depth--;
                        if ($depth === 0) {
                            return substr($str, $start, $i - $start + 1);
                        }
                    }
                }
            }
        }
        else if ($char === '[') {
            $depth = 0;
            $in_string = false;
            $escape = false;
            
            for ($i = $start; $i < strlen($str); $i++) {
                $c = $str[$i];
                
                if ($escape) {
                    $escape = false;
                    continue;
                }
                
                if ($c === '\\' && $in_string) {
                    $escape = true;
                    continue;
                }
                
                if ($c === '"' && !$escape) {
                    $in_string = !$in_string;
                    continue;
                }
                
                if (!$in_string) {
                    if ($c === '[') {
                        $depth++;
                    } else if ($c === ']') {
                        $depth--;
                        if ($depth === 0) {
                            return substr($str, $start, $i - $start + 1);
                        }
                    }
                }
            }
        }
        
        return null;
    }
    
    public function test_connection() {
        try {
            $this->get_supported_coins();
            return array(
                'success' => true,
                'message' => __('API connection successful', 'paystarsea-crypto-payment-gateway')
            );
        } catch (Exception $e) {
            return array(
                'success' => false,
                'message' => $e->getMessage()
            );
        }
    }
}
