<?php
/**
 * Plugin Name: PayStarSea Crypto Payment Gateway
 * Plugin URI: https://www.paystarsea.com/woocommerce-plugin
 * Description: Accept cryptocurrency payments (USDT, BTC, ETH) on your WooCommerce store via PayStarSea payment gateway. Supports TRC20, ERC20, BEP20 networks.
 * Version: 1.0.0
 * Author: PayStarSea
 * Author URI: https://www.paystarsea.com
 * Text Domain: paystarsea-crypto-payment-gateway
 * Domain Path: /languages
 * Requires at least: 5.8
 * Requires PHP: 7.4
 * WC requires at least: 6.0
 * WC tested up to: 9.6
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */

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

define('SEAXPAY_VERSION', '1.0.0');
define('SEAXPAY_PLUGIN_FILE', __FILE__);
define('SEAXPAY_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('SEAXPAY_PLUGIN_URL', plugin_dir_url(__FILE__));
define('SEAXPAY_PLUGIN_BASENAME', plugin_basename(__FILE__));
define('SEAXPAY_API_URL', 'https://openapi.paystarsea.com');

add_action('before_woocommerce_init', function() {
    if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
        \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
    }
});

function seaxpay_check_woocommerce() {
    if (!class_exists('WooCommerce')) {
        add_action('admin_notices', 'seaxpay_woocommerce_missing_notice');
        return false;
    }
    return true;
}

function seaxpay_woocommerce_missing_notice() {
    ?>
    <div class="error">
        <p><?php esc_html_e('SeaXPay Crypto Payment Gateway requires WooCommerce to be installed and active.', 'paystarsea-crypto-payment-gateway'); ?></p>
    </div>
    <?php
}

function seaxpay_check_php_version() {
    if (version_compare(PHP_VERSION, '7.4', '<')) {
        add_action('admin_notices', 'seaxpay_php_version_notice');
        return false;
    }
    return true;
}

function seaxpay_php_version_notice() {
    ?>
    <div class="error">
        <p><?php
        /* translators: %s: current PHP version */
        printf(esc_html__('SeaXPay Crypto Payment Gateway requires PHP 7.4 or higher. Your PHP version: %s', 'paystarsea-crypto-payment-gateway'), esc_html(PHP_VERSION)); ?></p>
    </div>
    <?php
}

function seaxpay_init() {
    if (!seaxpay_check_php_version()) {
        return;
    }
    
    if (!seaxpay_check_woocommerce()) {
        return;
    }
    
    if (!extension_loaded('bcmath')) {
        add_action('admin_notices', function() {
            ?>
            <div class="error">
                <p><?php esc_html_e('PayStarSea Crypto Payment Gateway requires the PHP bcmath extension. Please contact your hosting provider to enable it.', 'paystarsea-crypto-payment-gateway'); ?></p>
            </div>
            <?php
        });
        return;
    }
    
    require_once SEAXPAY_PLUGIN_DIR . 'includes/functions.php';
    require_once SEAXPAY_PLUGIN_DIR . 'includes/seaxpay-status-ssot.php';
    require_once SEAXPAY_PLUGIN_DIR . 'includes/class-seaxpay-gateway.php';
    require_once SEAXPAY_PLUGIN_DIR . 'includes/class-seaxpay-api-client.php';
    require_once SEAXPAY_PLUGIN_DIR . 'includes/class-seaxpay-webhook.php';
    
    if (is_admin()) {
        require_once SEAXPAY_PLUGIN_DIR . 'admin/class-seaxpay-admin.php';
    }
    
    add_filter('woocommerce_payment_gateways', 'seaxpay_add_gateway');
    
    add_action('woocommerce_blocks_loaded', 'seaxpay_woocommerce_blocks_support');
    
    
    add_action('init', 'seaxpay_add_endpoints');
    add_filter('query_vars', 'seaxpay_add_query_vars');
    add_action('template_redirect', 'seaxpay_handle_payment_endpoint');
}
add_action('plugins_loaded', 'seaxpay_init');

function seaxpay_add_endpoints() {
    add_rewrite_endpoint('seaxpay-payment', EP_ROOT | EP_PAGES);
}

function seaxpay_add_query_vars($vars) {
    $vars[] = 'seaxpay-payment';
    $vars[] = 'order_id';
    $vars[] = 'key';
    return $vars;
}

function seaxpay_handle_payment_endpoint() {
    global $wp_query;
    
    if (!isset($wp_query->query_vars['seaxpay-payment'])) {
        return;
    }
    
    
    seaxpay_handle_payment_page();
}

function seaxpay_handle_payment_page() {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $order_id = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0;
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $order_key = isset($_GET['key']) ? sanitize_text_field(wp_unslash($_GET['key'])) : '';
    
    if (!$order_id || !$order_key) {
        wp_die(esc_html__('Invalid order', 'paystarsea-crypto-payment-gateway'));
    }
    
    $order = wc_get_order($order_id);
    
    if (!$order || $order->get_order_key() !== $order_key) {
        wp_die(esc_html__('Invalid order', 'paystarsea-crypto-payment-gateway'));
    }
    
    $seaxpay_order = seaxpay_get_order_by_wc_id($order_id);
    
    if ($seaxpay_order && $seaxpay_order->status === 'pending' && $seaxpay_order->expire_time) {
        $expire_timestamp = strtotime($seaxpay_order->expire_time . ' UTC');
        $current_utc_timestamp = time();
        
        if ($expire_timestamp !== false && $expire_timestamp < $current_utc_timestamp) {
            global $wpdb;
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                $wpdb->prefix . 'seaxpay_orders',
                array('status' => 'expired', 'update_time' => gmdate('Y-m-d H:i:s')),
                array('id' => $seaxpay_order->id)
            );
            
        
            if ($order->get_status() === 'pending') {
                remove_action('woocommerce_order_status_changed', 'seaxpay_sync_order_status', 10);
                $order->update_status('cancelled', __('Payment expired - time limit reached.', 'paystarsea-crypto-payment-gateway'));
                add_action('woocommerce_order_status_changed', 'seaxpay_sync_order_status', 10, 4);
            }
            
            $seaxpay_order = seaxpay_get_order_by_wc_id($order_id);
            
            seaxpay_log('order', 'Order expired on page access', $order_id, $seaxpay_order->platform_order_no ?? '', null, null);
        }
    }
    
    $platform_address = $seaxpay_order ? $seaxpay_order->customer_address : $order->get_meta('_seaxpay_platform_address');
    $selected_coin = $seaxpay_order ? $seaxpay_order->coin : $order->get_meta('_seaxpay_coin');
    $expire_time = $seaxpay_order ? $seaxpay_order->expire_time : $order->get_meta('_seaxpay_expire_time');
    $platform_order_no = $seaxpay_order ? $seaxpay_order->platform_order_no : $order->get_meta('_seaxpay_platform_order_no');
    $is_expired = false;
    if ($seaxpay_order && $seaxpay_order->status === 'expired') {
        $is_expired = true;
    } elseif ($expire_time) {
        $expire_timestamp = strtotime($expire_time . ' UTC');
        $is_expired = ($expire_timestamp !== false && $expire_timestamp < time());
    }

    seaxpay_enqueue_payment_page_assets($order, $is_expired, $platform_address, $expire_time, $selected_coin, $platform_order_no);

    include SEAXPAY_PLUGIN_DIR . 'templates/payment-page.php';
    exit;
}

function seaxpay_add_gateway($gateways) {
    $gateways[] = 'WC_Gateway_SeaxPay';
    return $gateways;
}

function seaxpay_woocommerce_blocks_support() {
    if (class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType')) {
        require_once SEAXPAY_PLUGIN_DIR . 'includes/blocks/class-seaxpay-gateway-blocks.php';
        
        add_action(
            'woocommerce_blocks_payment_method_type_registration',
            function(Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) {
                $payment_method_registry->register(new SeaXPay_Blocks_Support());
            }
        );
    }
}

function seaxpay_activate() {
    global $wpdb;
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    
    $charset_collate = $wpdb->get_charset_collate();
    
    $sql_orders = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}seaxpay_orders` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `wc_order_id` bigint(20) unsigned NOT NULL COMMENT 'WooCommerce order ID',
      `user_id` bigint(20) unsigned DEFAULT NULL COMMENT 'WordPress user ID',
      `platform_order_no` varchar(64) NOT NULL COMMENT 'Platform order number',
      `local_order_no` varchar(64) NOT NULL COMMENT 'Local order number (WC_xxxxx)',
      `coin` varchar(20) NOT NULL COMMENT 'Cryptocurrency symbol (USDT, BTC, ETH)',
      `network` varchar(20) NOT NULL COMMENT 'Blockchain network (TRC20, ERC20, BEP20)',
      `fiat_amount` decimal(10,2) NOT NULL COMMENT 'Fiat currency amount',
      `fiat_currency` varchar(10) NOT NULL DEFAULT 'USD' COMMENT 'Fiat currency code',
      `crypto_amount` varchar(50) DEFAULT NULL COMMENT 'Cryptocurrency amount',
      `exchange_rate` decimal(20,8) DEFAULT NULL COMMENT 'Exchange rate at order creation',
      `customer_address` varchar(100) DEFAULT NULL COMMENT 'Customer wallet address (filled after payment)',
      `address_mode` varchar(20) DEFAULT 'fingerprint' COMMENT 'Address mode (hd or fingerprint)',
      `tx_hash` varchar(100) DEFAULT NULL COMMENT 'Blockchain transaction hash',
      `status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT 'Order status (pending, paid, expired, failed)',
      `platform_callback_data` text COMMENT 'Platform webhook callback data (JSON)',
      `expire_time` datetime DEFAULT NULL COMMENT 'Payment expiration time',
      `paid_time` datetime DEFAULT NULL COMMENT 'Payment completion time',
      `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time',
      `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Last update time',
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_platform_order_no` (`platform_order_no`),
      KEY `idx_wc_order_id` (`wc_order_id`),
      KEY `idx_local_order_no` (`local_order_no`),
      KEY `idx_status` (`status`),
      KEY `idx_create_time` (`create_time`)
    ) $charset_collate ENGINE=InnoDB COMMENT='SeaXPay payment orders';";
    
    $sql_logs = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}seaxpay_logs` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `log_type` varchar(20) NOT NULL COMMENT 'Log type (api, webhook, order, error)',
      `wc_order_id` bigint(20) unsigned DEFAULT NULL COMMENT 'Related WooCommerce order ID',
      `platform_order_no` varchar(64) DEFAULT NULL COMMENT 'Related platform order number',
      `message` text NOT NULL COMMENT 'Log message',
      `request_data` text COMMENT 'Request data (JSON, sensitive info removed)',
      `response_data` text COMMENT 'Response data (JSON, sensitive info removed)',
      `ip_address` varchar(45) DEFAULT NULL COMMENT 'Request IP address',
      `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time',
      PRIMARY KEY (`id`),
      KEY `idx_log_type` (`log_type`),
      KEY `idx_wc_order_id` (`wc_order_id`),
      KEY `idx_platform_order_no` (`platform_order_no`),
      KEY `idx_create_time` (`create_time`)
    ) $charset_collate ENGINE=InnoDB COMMENT='SeaXPay operation logs';";
    
    dbDelta($sql_orders);
    dbDelta($sql_logs);
    
    $orders_table = "{$wpdb->prefix}seaxpay_orders";
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $column_exists = $wpdb->get_results("SHOW COLUMNS FROM `{$orders_table}` LIKE 'address_mode'");
    if (empty($column_exists)) {
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->query("ALTER TABLE `{$orders_table}` ADD COLUMN `address_mode` varchar(20) DEFAULT 'fingerprint' COMMENT 'Address mode (hd or fingerprint)' AFTER `customer_address`");
    }
    
    flush_rewrite_rules();
    
    seaxpay_schedule_expired_orders_check();
}
register_activation_hook(__FILE__, 'seaxpay_activate');


function seaxpay_schedule_expired_orders_check() {
    if (function_exists('as_schedule_recurring_action') && !as_next_scheduled_action('seaxpay_check_expired_orders')) {
        as_schedule_recurring_action(time(), HOUR_IN_SECONDS, 'seaxpay_check_expired_orders', array(), 'paystarsea-crypto-payment-gateway');
    } elseif (!wp_next_scheduled('seaxpay_check_expired_orders')) {
        wp_schedule_event(time(), 'hourly', 'seaxpay_check_expired_orders');
    }
}

function seaxpay_ensure_scheduled_tasks() {
    $needs_schedule = false;
    
    if (function_exists('as_next_scheduled_action')) {
        $needs_schedule = !as_next_scheduled_action('seaxpay_check_expired_orders');
    } else {
        $needs_schedule = !wp_next_scheduled('seaxpay_check_expired_orders');
    }
    
    if ($needs_schedule) {
        seaxpay_schedule_expired_orders_check();
    }
}
add_action('init', 'seaxpay_ensure_scheduled_tasks');

function seaxpay_check_db_migration() {
    $current_db_version = get_option('seaxpay_db_version', '1.0.0');
    $target_db_version = '1.1.0';
    
    if (version_compare($current_db_version, $target_db_version, '<')) {
        global $wpdb;
        $orders_table = "{$wpdb->prefix}seaxpay_orders";
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $column_exists = $wpdb->get_results("SHOW COLUMNS FROM `{$orders_table}` LIKE 'address_mode'");
        if (empty($column_exists)) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->query("ALTER TABLE `{$orders_table}` ADD COLUMN `address_mode` varchar(20) DEFAULT 'fingerprint' COMMENT 'Address mode (hd or fingerprint)' AFTER `customer_address`");
        }
        
        update_option('seaxpay_db_version', $target_db_version);
    }
}
add_action('init', 'seaxpay_check_db_migration');

function seaxpay_deactivate() {
    if (function_exists('as_unschedule_all_actions')) {
        as_unschedule_all_actions('seaxpay_check_expired_orders');
    }
    wp_clear_scheduled_hook('seaxpay_check_expired_orders');
    flush_rewrite_rules();
}
register_deactivation_hook(__FILE__, 'seaxpay_deactivate');

add_action('wp_ajax_seaxpay_create_order', 'seaxpay_ajax_create_order');
add_action('wp_ajax_nopriv_seaxpay_create_order', 'seaxpay_ajax_create_order');

function seaxpay_ajax_create_order() {
    check_ajax_referer('seaxpay_payment', 'nonce');

    $order_id = isset($_POST['order_id']) ? intval(wp_unslash($_POST['order_id'])) : 0;
    $order_key = isset($_POST['order_key']) ? sanitize_text_field(wp_unslash($_POST['order_key'])) : '';
    $coin = isset($_POST['coin']) ? sanitize_text_field(wp_unslash($_POST['coin'])) : '';
    $network = isset($_POST['network']) ? sanitize_text_field(wp_unslash($_POST['network'])) : '';

    if (!$order_id || !$order_key || !$coin || !$network) {
        wp_send_json_error(__('Invalid parameters', 'paystarsea-crypto-payment-gateway'));
    }

    $order = wc_get_order($order_id);

    if (!$order || $order->get_order_key() !== $order_key) {
        wp_send_json_error(__('Invalid order', 'paystarsea-crypto-payment-gateway'));
    }

    global $wpdb;
    $orders_table = "{$wpdb->prefix}seaxpay_orders";

    if (function_exists('seaxpay_find_reusable_order')) {
        $existing = seaxpay_find_reusable_order($order_id, $coin, $network);
    } else {
        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $existing = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$orders_table} WHERE wc_order_id = %d AND coin = %s AND network = %s AND status IN ('pending','processing','confirming') ORDER BY id DESC LIMIT 1",
            $order_id, $coin, $network
        ));
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    }

    if ($existing) {
        seaxpay_log('order', 'Reusing existing pending order for coin switch', $order_id, $existing->platform_order_no, null, null);
        wp_send_json_success(array(
            'platform_order_no' => $existing->platform_order_no
        ));
    }

    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $existing_other = $wpdb->get_row($wpdb->prepare(
        "SELECT * FROM {$orders_table} WHERE wc_order_id = %d AND coin = %s AND network = %s ORDER BY id DESC LIMIT 1",
        $order_id, $coin, $network
    ));
    // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

    try {
        $api_client = new SeaXPay_API_Client();

        $merchant_order_no = seaxpay_build_merchant_order_no($order_id, $coin, $network);

        $response = $api_client->create_order(
            $merchant_order_no,
            $order->get_total(),
            $order->get_currency(),
            $coin,
            $network,
            WC()->api_request_url('seaxpay_webhook'),
            $order->get_checkout_order_received_url()
        );

        $platform_order_no = $response['orderNo'] ?? null;
        $payment_address   = $response['paymentAddress'] ?? null;
        $crypto_amount     = isset($response['cryptoAmount']) ? strval($response['cryptoAmount']) : null;
        $exchange_rate     = $response['exchangeRate'] ?? null;
        $address_mode      = $response['addressMode'] ?? 'fingerprint';
        $expire_time_ms    = $response['expireTime'] ?? null;
        $expire_time_fmt   = $expire_time_ms ? gmdate('Y-m-d H:i:s', intval($expire_time_ms) / 1000) : null;

        if (empty($platform_order_no) || empty($payment_address)) {
            seaxpay_log('error', 'API response missing orderNo or paymentAddress', $order_id, null,
                seaxpay_sanitize_for_log($response), null);
            throw new Exception(__('Payment gateway returned invalid response (missing address)', 'paystarsea-crypto-payment-gateway'));
        }

        $record_fields = array(
            'wc_order_id'       => $order_id,
            'user_id'           => $order->get_user_id(),
            'platform_order_no' => $platform_order_no,
            'local_order_no'    => $merchant_order_no,
            'coin'              => $coin,
            'network'           => $network,
            'fiat_amount'       => $order->get_total(),
            'fiat_currency'     => $order->get_currency(),
            'crypto_amount'     => $crypto_amount,
            'exchange_rate'     => $exchange_rate,
            'customer_address'  => $payment_address,
            'address_mode'      => $address_mode,
            'status'            => 'pending',
            'expire_time'       => $expire_time_fmt,
        );

        if ($existing_other) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $updated = $wpdb->update($orders_table, $record_fields, array('id' => $existing_other->id));
            if ($updated === false) {
                seaxpay_log('error', 'Failed to refresh seaxpay_orders: ' . $wpdb->last_error,
                    $order_id, $platform_order_no, null, null);
                throw new Exception(__('Database update failed', 'paystarsea-crypto-payment-gateway'));
            }
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $inserted = $wpdb->insert($orders_table, $record_fields);
            if ($inserted === false) {
                seaxpay_log('error', 'Failed to insert seaxpay_orders: ' . $wpdb->last_error,
                    $order_id, $platform_order_no, null, null);
                throw new Exception(__('Database insert failed', 'paystarsea-crypto-payment-gateway'));
            }
        }

        $order->update_meta_data('_seaxpay_coin', $coin);
        $order->update_meta_data('_seaxpay_network', $network);
        $order->update_meta_data('_seaxpay_platform_order_no', $platform_order_no);
        $order->update_meta_data('_seaxpay_crypto_amount', $crypto_amount);
        $order->update_meta_data('_seaxpay_platform_address', $payment_address);
        $order->update_meta_data('_seaxpay_address_mode', $address_mode);
        if ($expire_time_fmt) {
            $order->update_meta_data('_seaxpay_expire_time', $expire_time_fmt);
        }
        $order->save();

        seaxpay_log('order', 'Order created successfully via AJAX', $order_id, $platform_order_no, null, null);

        wp_send_json_success(array(
            'platform_order_no' => $platform_order_no
        ));

    } catch (Exception $e) {
        seaxpay_log('error', 'Failed to create order: ' . $e->getMessage(), $order_id, null, null, null);
        wp_send_json_error($e->getMessage());
    }
}

function seaxpay_build_merchant_order_no($wc_order_id, $coin, $network) {
    global $wpdb;
    $base = intval($wc_order_id) . '_' . strtolower($coin) . '_' . strtolower($network);
    if (!$wpdb) {
        return $base;
    }
    $table = $wpdb->prefix . 'seaxpay_orders';
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $count = (int) $wpdb->get_var($wpdb->prepare(
        "SELECT COUNT(*) FROM {$table} WHERE wc_order_id = %d AND LOWER(coin) = %s AND LOWER(network) = %s",
        intval($wc_order_id), strtolower($coin), strtolower($network)
    ));
    // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    if ($count <= 0) {
        return $base;
    }
    return $base . '_r' . $count;
}

add_action('wp_ajax_seaxpay_get_payment_address', 'seaxpay_ajax_get_payment_address');
add_action('wp_ajax_nopriv_seaxpay_get_payment_address', 'seaxpay_ajax_get_payment_address');

function seaxpay_ajax_get_payment_address() {
    check_ajax_referer('seaxpay_payment', 'nonce');
    
    $platform_order_no = isset($_POST['platform_order_no']) ? sanitize_text_field(wp_unslash($_POST['platform_order_no'])) : '';
    
    if (!$platform_order_no) {
        wp_send_json_error(__('Invalid order number', 'paystarsea-crypto-payment-gateway'));
    }
    
    $seaxpay_order = seaxpay_get_order_by_platform_no($platform_order_no);
    
    if (!$seaxpay_order) {
        wp_send_json_error(__('Order not found', 'paystarsea-crypto-payment-gateway'));
    }
    
    $address = !empty($seaxpay_order->customer_address) ? $seaxpay_order->customer_address : '';

    if (empty($address)) {
        seaxpay_log('error', 'Payment address unavailable (customer_address empty); refusing to fallback',
            $seaxpay_order->wc_order_id, $platform_order_no, null, null);
        wp_send_json_error(__('Payment address is not ready yet, please refresh the page or retry', 'paystarsea-crypto-payment-gateway'));
        return;
    }

    wp_send_json_success(array(
        'address' => $address,
        'qrcode_data' => $address
    ));
}

add_action('wp_ajax_seaxpay_check_order_status', 'seaxpay_ajax_check_order_status');
add_action('wp_ajax_nopriv_seaxpay_check_order_status', 'seaxpay_ajax_check_order_status');

function seaxpay_ajax_check_order_status() {
    check_ajax_referer('seaxpay_payment', 'nonce');
    
    $platform_order_no = isset($_POST['platform_order_no']) ? sanitize_text_field(wp_unslash($_POST['platform_order_no'])) : '';
    
    if (!$platform_order_no) {
        wp_send_json_error(__('Invalid order number', 'paystarsea-crypto-payment-gateway'));
    }
    
    $seaxpay_order = seaxpay_get_order_by_platform_no($platform_order_no);
    
    if (!$seaxpay_order) {
        wp_send_json_error(__('Order not found', 'paystarsea-crypto-payment-gateway'));
    }
    
    $result = array(
        'status' => $seaxpay_order->status,
        'tx_hash' => $seaxpay_order->tx_hash
    );

    try {
        $api_client = new SeaXPay_API_Client();
        $live = $api_client->get_order_status($platform_order_no);
        if (is_array($live)) {
            if (isset($live['cryptoAmount'])) {
                $result['crypto_amount'] = strval($live['cryptoAmount']);
            }
            if (isset($live['receivedAmount'])) {
                $result['received_amount'] = strval($live['receivedAmount']);
            }
            if (isset($live['remainingAmount'])) {
                $result['remaining_amount'] = strval($live['remainingAmount']);
            }
            if (isset($live['expireTime'])) {
                $result['expire_time'] = strval($live['expireTime']);
            }
        }
    } catch (Exception $e) {
        seaxpay_log('error', 'Live order status fetch failed: ' . $e->getMessage(), null, $platform_order_no, null, null);
    }

    wp_send_json_success($result);
}

add_action('wp_ajax_seaxpay_get_quote', 'seaxpay_ajax_get_quote');
add_action('wp_ajax_nopriv_seaxpay_get_quote', 'seaxpay_ajax_get_quote');

function seaxpay_ajax_get_quote() {
    check_ajax_referer('seaxpay_blocks', 'nonce');
    
    $coin = isset($_POST['coin']) ? sanitize_text_field(wp_unslash($_POST['coin'])) : '';
    $network = isset($_POST['network']) ? sanitize_text_field(wp_unslash($_POST['network'])) : '';
    $fiat_amount = isset($_POST['fiat_amount']) ? floatval(wp_unslash($_POST['fiat_amount'])) : 0;
    $fiat_currency = isset($_POST['fiat_currency']) ? sanitize_text_field(wp_unslash($_POST['fiat_currency'])) : 'USD';
    
    if (!$coin || !$network || $fiat_amount <= 0) {
        wp_send_json_error(__('Invalid parameters', 'paystarsea-crypto-payment-gateway'));
    }
    
    try {
        $api_client = new SeaXPay_API_Client();
        
        $quote_response = $api_client->get_quote($fiat_amount, $fiat_currency, $coin, $network);
        
        $exchange_rate = $quote_response['exchangeRate'] ?? '1';
        $crypto_amount = $quote_response['cryptoAmount'] ?? strval($fiat_amount);
        
        wp_send_json_success(array(
            'coin' => $coin,
            'network' => $network,
            'fiat_amount' => $fiat_amount,
            'fiat_currency' => $fiat_currency,
            'crypto_amount' => $crypto_amount,
            'exchange_rate' => $exchange_rate
        ));
        
    } catch (Exception $e) {
        seaxpay_log('error', 'Failed to get quote: ' . $e->getMessage(), null, null, null, null);
        wp_send_json_error($e->getMessage());
    }
}

add_action('wp_ajax_seaxpay_get_coins_for_settings', 'seaxpay_ajax_get_coins_for_settings');

function seaxpay_ajax_get_coins_for_settings() {
    check_ajax_referer('seaxpay_admin', 'nonce');
    
    if (!current_user_can('manage_woocommerce')) {
        wp_send_json_error(__('Permission denied', 'paystarsea-crypto-payment-gateway'));
    }
    
    try {
        $merchant_no = isset($_POST['merchant_no']) ? sanitize_text_field(wp_unslash($_POST['merchant_no'])) : null;
        
        if (!$merchant_no) {
            wp_send_json_error(__('Merchant No is required', 'paystarsea-crypto-payment-gateway'));
        }
        
        $api_client = new SeaXPay_API_Client();
        $coins_data = $api_client->get_supported_coins($merchant_no);
        
        $supported_coins = array();
        foreach ($coins_data as $coin_config) {
            $coin = $coin_config['coin'];
            $network = $coin_config['network'];
            
            if (!isset($supported_coins[$coin])) {
                $supported_coins[$coin] = array(
                    'name' => $coin_config['coinName'] ?? $coin,
                    'networks' => array()
                );
            }
            
            $supported_coins[$coin]['networks'][$network] = array(
                'name' => $coin_config['networkName'] ?? $network,
                'min_amount_usd' => isset($coin_config['minAmountUsd']) ? floatval($coin_config['minAmountUsd']) : null,
                'recommended' => !empty($coin_config['recommendedForEcommerce'])
            );
        }
        
        $enabled_coins_json = get_option('seaxpay_enabled_coins_' . $merchant_no, '');
        $enabled_networks_json = get_option('seaxpay_enabled_networks_' . $merchant_no, '');
        
        $enabled_coins_json = stripslashes($enabled_coins_json);
        $enabled_networks_json = stripslashes($enabled_networks_json);
        
        $enabled_coins = json_decode($enabled_coins_json, true);
        $enabled_networks = json_decode($enabled_networks_json, true);
        
        wp_send_json(array(
            'success' => true,
            'data' => $supported_coins,
            'enabled_coins' => $enabled_coins ?: new stdClass(),
            'enabled_networks' => $enabled_networks ?: new stdClass()
        ));
        
    } catch (Exception $e) {
        seaxpay_log('error', 'Failed to get coins for settings: ' . $e->getMessage(), null, null, null, null);
        wp_send_json_error($e->getMessage());
    }
}

add_action('wp_ajax_seaxpay_save_coins_settings', 'seaxpay_ajax_save_coins_settings');

function seaxpay_ajax_save_coins_settings() {
    check_ajax_referer('seaxpay_admin', 'nonce');
    
    if (!current_user_can('manage_woocommerce')) {
        wp_send_json_error(__('Permission denied', 'paystarsea-crypto-payment-gateway'));
    }
    
    try {
        $merchant_no = isset($_POST['merchant_no']) ? sanitize_text_field(wp_unslash($_POST['merchant_no'])) : null;
        $enabled_coins = isset($_POST['enabled_coins']) ? sanitize_text_field(wp_unslash($_POST['enabled_coins'])) : '';
        $enabled_networks = isset($_POST['enabled_networks']) ? sanitize_text_field(wp_unslash($_POST['enabled_networks'])) : '';
        
        if (!$merchant_no) {
            wp_send_json_error(__('Merchant No is required', 'paystarsea-crypto-payment-gateway'));
        }
        
        update_option('seaxpay_enabled_coins_' . $merchant_no, $enabled_coins);
        update_option('seaxpay_enabled_networks_' . $merchant_no, $enabled_networks);
        
        delete_transient('seaxpay_supported_coins_' . $merchant_no);
        delete_transient('seaxpay_enabled_coins_' . $merchant_no);
        delete_transient('seaxpay_enabled_networks_' . $merchant_no);
        
        wp_send_json_success(__('Settings saved successfully', 'paystarsea-crypto-payment-gateway'));
        
    } catch (Exception $e) {
        seaxpay_log('error', 'Failed to save coins settings: ' . $e->getMessage(), null, null, null, null);
        wp_send_json_error($e->getMessage());
    }
}

function seaxpay_sync_order_status($order_id, $from_status, $to_status, $order) {
    global $wpdb;
    $table = $wpdb->prefix . 'seaxpay_orders';
    
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $seaxpay_order = $wpdb->get_row($wpdb->prepare(
        "SELECT * FROM {$table} WHERE wc_order_id = %d",
        $order_id
    ));
    // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    
    if (!$seaxpay_order) {
        return;
    }

    if (in_array($seaxpay_order->status, array('completed', 'settled', 'risk_refunded', 'risk_rejected', 'risk_frozen'), true)
        && in_array($to_status, array('completed', 'processing'), true)) {
        return;
    }
    
    $status_map = array(
        'cancelled' => 'expired',
        'failed'    => 'failed',
        'refunded'  => 'refunded',
    );
    
    if (isset($status_map[$to_status])) {
        $update_data = array(
            'status' => $status_map[$to_status],
            'update_time' => gmdate('Y-m-d H:i:s')
        );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update($table, $update_data, array('wc_order_id' => $order_id));
        
        seaxpay_log('order', sprintf('Order status synced: WC %s -> SeaxPay %s', $to_status, $status_map[$to_status]), $order_id, $seaxpay_order->platform_order_no, null, null);
    }
}
add_action('woocommerce_order_status_changed', 'seaxpay_sync_order_status', 10, 4);


function seaxpay_check_expired_orders() {
    global $wpdb;
    $table = $wpdb->prefix . 'seaxpay_orders';
    
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $expired_orders = $wpdb->get_results($wpdb->prepare(
        "SELECT id, wc_order_id, platform_order_no FROM {$table} WHERE status = %s AND expire_time IS NOT NULL AND expire_time < UTC_TIMESTAMP()",
        'pending'
    ));
    // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    
    if (empty($expired_orders)) {
        return;
    }
    
    foreach ($expired_orders as $row) {
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update(
            $table,
            array(
                'status' => 'expired',
                'update_time' => gmdate('Y-m-d H:i:s')
            ),
            array('id' => $row->id)
        );
        
        $order = wc_get_order($row->wc_order_id);
        if ($order && $order->get_status() === 'pending') {
            
            remove_action('woocommerce_order_status_changed', 'seaxpay_sync_order_status', 10);
            $order->update_status('cancelled', __('Payment expired - time limit reached.', 'paystarsea-crypto-payment-gateway'));
            add_action('woocommerce_order_status_changed', 'seaxpay_sync_order_status', 10, 4);
        }
        
        seaxpay_log('order', 'Order expired by cron job', $row->wc_order_id, $row->platform_order_no, null, null);
    }
}
add_action('seaxpay_check_expired_orders', 'seaxpay_check_expired_orders');
