<?php
/**
 * StablePay Webhook 处理器
 *
 * @package StablePay_WooCommerce
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

/**
 * StablePay_Webhook_Handler 类
 *
 * 负责接收和处理 StablePay Webhook 通知
 */
class StablePay_Webhook_Handler {
    /**
     * Webhook Secret
     *
     * @var string
     */
    private $webhook_secret;

    /**
     * 日志记录器
     *
     * @var StablePay_Logger
     */
    private $logger;

    /**
     * 构造函数
     *
     * @param string $webhook_secret Webhook 密钥
     * @param StablePay_Logger $logger 日志记录器
     */
    public function __construct($webhook_secret, $logger = null) {
        $this->webhook_secret = $webhook_secret;
        $this->logger = $logger ? $logger : new StablePay_Logger();

        // 注册 REST API 端点
        add_action('rest_api_init', array($this, 'register_webhook_endpoint'));
    }

    /**
     * 注册 Webhook REST API 端点
     */
    public function register_webhook_endpoint() {
        register_rest_route('stablepay/v1', '/webhook', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_webhook'),
            'permission_callback' => '__return_true', // 公开端点，通过签名验证
        ));
    }

    /**
     * 处理 Webhook 请求
     *
     * @param WP_REST_Request $request 请求对象
     * @return WP_REST_Response 响应对象
     */
    public function handle_webhook($request) {
        // 记录 Webhook 请求入口
        $this->logger->info('收到 Webhook 请求', array(
            'remote_addr' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown',
            'user_agent' => $request->get_header('user-agent'),
            'content_type' => $request->get_header('content-type'),
        ));

        // 获取请求头
        $signature = $request->get_header('stablepay-signature');
        $timestamp = $request->get_header('stablepay-timestamp');

        // 获取原始请求体（用于签名验证）
        $raw_body = $request->get_body();

        $this->logger->debug('Webhook 请求头', array(
            'has_signature' => !empty($signature),
            'has_timestamp' => !empty($timestamp),
            'timestamp' => $timestamp,
            'body_length' => strlen($raw_body),
        ));

        // 验证签名
        if (!$this->verify_signature($signature, $timestamp, $raw_body)) {
            $this->logger->error('Webhook 签名验证失败', array(
                'signature' => $signature ? substr($signature, 0, 16) . '...' : null,
                'timestamp' => $timestamp,
                'current_time' => time(),
                'time_diff' => $timestamp ? abs(time() - intval($timestamp)) : null,
            ));
            return new WP_REST_Response(array(
                'status' => 'error',
                'message' => 'Invalid signature',
            ), 401);
        }

        $this->logger->debug('Webhook 签名验证通过');

        // 解析请求体
        $body = json_decode($raw_body, true);

        // 验证请求体
        if (empty($body) || !isset($body['type']) || !isset($body['data'])) {
            $this->logger->error('Webhook 请求体格式错误', array(
                'body_empty' => empty($body),
                'has_type' => isset($body['type']),
                'has_data' => isset($body['data']),
                'body_keys' => is_array($body) ? array_keys($body) : null,
            ));
            return new WP_REST_Response(array(
                'status' => 'error',
                'message' => 'Invalid request body',
            ), 400);
        }

        // 提取事件信息
        $event_id = isset($body['id']) ? $body['id'] : '';
        $event_type = $body['type'];
        $event_data = $body['data']['object'];

        // 检查幂等性
        if ($this->is_event_processed($event_id)) {
            $this->logger->info('Webhook 事件已处理过（幂等）', array(
                'event_id' => $event_id,
                'event_type' => $event_type,
            ));
            return new WP_REST_Response(array(
                'status' => 'success',
                'message' => 'Event already processed',
            ), 200);
        }

        // 记录日志
        $this->logger->info('接收 Webhook 通知', array(
            'event_id' => $event_id,
            'event_type' => $event_type,
            'session_id' => isset($event_data['session_id']) ? $event_data['session_id'] : '',
        ));

        // 处理事件
        try {
            $this->process_event($event_type, $event_data);

            // 标记事件已处理
            $this->mark_event_processed($event_id);

            return new WP_REST_Response(array(
                'status' => 'success',
                'message' => 'Webhook received',
            ), 200);
        } catch (Exception $e) {
            $this->logger->error('Webhook 处理失败', array(
                'event_id' => $event_id,
                'event_type' => $event_type,
                'error' => $e->getMessage(),
            ));
            return new WP_REST_Response(array(
                'status' => 'error',
                'message' => $e->getMessage(),
            ), 500);
        }
    }

    /**
     * 验证 Webhook 签名
     *
     * @param string $signature 接收到的签名
     * @param int $timestamp 接收到的时间戳
     * @param string $body 原始请求体
     * @return bool 签名是否有效
     */
    private function verify_signature($signature, $timestamp, $body) {
        return StablePay_API_Client::verify_webhook_signature(
            $signature,
            $timestamp,
            $body,
            $this->webhook_secret
        );
    }

    /**
     * 处理 Webhook 事件
     *
     * @param string $event_type 事件类型
     * @param array $event_data 事件数据
     * @throws Exception 处理失败时抛出异常
     */
    private function process_event($event_type, $event_data) {
        $this->logger->debug('开始处理 Webhook 事件', array(
            'event_type' => $event_type,
            'session_id' => isset($event_data['session_id']) ? $event_data['session_id'] : null,
            'metadata' => isset($event_data['metadata']) ? $event_data['metadata'] : null,
        ));

        // 提取订单 ID
        $wc_order_id = isset($event_data['metadata']['wc_order_id']) ? $event_data['metadata']['wc_order_id'] : '';

        if (empty($wc_order_id)) {
            $this->logger->error('事件处理失败：订单 ID 缺失', array(
                'event_type' => $event_type,
                'event_data_keys' => array_keys($event_data),
            ));
            throw new Exception('订单 ID 缺失');
        }

        // 获取订单
        $order = wc_get_order($wc_order_id);

        if (!$order) {
            $this->logger->error('事件处理失败：订单不存在', array(
                'wc_order_id' => $wc_order_id,
                'event_type' => $event_type,
            ));
            throw new Exception('订单不存在：' . $wc_order_id);
        }

        $this->logger->debug('找到关联订单', array(
            'order_id' => $order->get_id(),
            'order_status' => $order->get_status(),
            'payment_method' => $order->get_payment_method(),
        ));

        // 验证订单支付方式
        if ($order->get_payment_method() !== 'stablepay') {
            $this->logger->error('事件处理失败：订单支付方式不匹配', array(
                'order_id' => $order->get_id(),
                'payment_method' => $order->get_payment_method(),
            ));
            throw new Exception('订单支付方式不是 StablePay');
        }

        // 根据事件类型处理
        $this->logger->info('处理事件', array(
            'event_type' => $event_type,
            'order_id' => $order->get_id(),
        ));

        switch ($event_type) {
            case 'payment.completed':
                $this->handle_payment_completed($order, $event_data);
                break;

            case 'payment.failed':
                $this->handle_payment_failed($order, $event_data);
                break;

            case 'payment.expired':
                $this->handle_payment_expired($order, $event_data);
                break;

            case 'payment.pending':
                $this->handle_payment_pending($order, $event_data);
                break;

            case 'refund.succeeded':
                $this->handle_refund_succeeded($order, $event_data);
                break;

            case 'refund.failed':
                $this->handle_refund_failed($order, $event_data);
                break;

            default:
                $this->logger->warning('未知的事件类型，跳过处理', array(
                    'event_type' => $event_type,
                    'order_id' => $order->get_id(),
                ));
        }

        $this->logger->debug('事件处理完成', array(
            'event_type' => $event_type,
            'order_id' => $order->get_id(),
        ));
    }

    /**
     * 处理支付成功事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_payment_completed($order, $event_data) {
        $this->logger->debug('处理支付成功事件', array(
            'order_id' => $order->get_id(),
            'order_status' => $order->get_status(),
            'is_paid' => $order->is_paid(),
            'event_amount' => isset($event_data['amount']) ? $event_data['amount'] : null,
            'event_currency' => isset($event_data['currency']) ? $event_data['currency'] : null,
        ));

        // 检查订单是否已支付
        if ($order->is_paid()) {
            $this->logger->info('订单已支付，跳过处理', array('order_id' => $order->get_id()));
            return;
        }

        // 验证金额（稳定币与 USD 按 1:1 换算）
        $order_total = (float)$order->get_total();
        $order_currency = strtoupper($order->get_currency());
        $paid_amount = isset($event_data['amount']) ? (float)$event_data['amount'] : 0;
        $paid_currency = isset($event_data['currency']) ? strtoupper($event_data['currency']) : '';

        // 稳定币列表（与 USD 1:1 换算）
        $stablecoins = array('USDT', 'USDC');

        $this->logger->debug('验证支付金额', array(
            'order_id' => $order->get_id(),
            'order_total' => $order_total,
            'order_currency' => $order_currency,
            'paid_amount' => $paid_amount,
            'paid_currency' => $paid_currency,
        ));

        // 仅当订单币种为 USD 且支付币种为稳定币时进行金额校验（1:1 换算）
        // 其他币种组合不校验金额，直接通过
        $should_validate = ($order_currency === 'USD' && in_array($paid_currency, $stablecoins));

        if ($should_validate && abs($order_total - $paid_amount) > 0.01) {
            // 金额不匹配，标记为等待审核
            $order->update_status('on-hold', sprintf(
                __('支付金额不匹配。订单金额：%s %s，实付金额：%s %s', 'stablepay-woocommerce'),
                $order_total,
                $order_currency,
                $paid_amount,
                $paid_currency
            ));
            $this->logger->warning('支付金额不匹配，订单置为等待审核', array(
                'order_id' => $order->get_id(),
                'order_total' => $order_total,
                'order_currency' => $order_currency,
                'paid_amount' => $paid_amount,
                'paid_currency' => $paid_currency,
            ));
            return;
        }

        // 保存交易信息
        $this->save_transaction_info($order, $event_data);

        // 标记订单为已支付
        $order->payment_complete($event_data['session_id']);

        // 添加订单备注
        $note = sprintf(
            __('StablePay 支付成功。交易哈希：%s', 'stablepay-woocommerce'),
            isset($event_data['transaction']['tx_hash']) ? $event_data['transaction']['tx_hash'] : ''
        );
        $order->add_order_note($note);

        $this->logger->info('订单支付成功', array(
            'order_id' => $order->get_id(),
            'session_id' => $event_data['session_id'],
            'tx_hash' => isset($event_data['transaction']['tx_hash']) ? $event_data['transaction']['tx_hash'] : null,
        ));
    }

    /**
     * 处理支付失败事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_payment_failed($order, $event_data) {
        $this->logger->debug('处理支付失败事件', array(
            'order_id' => $order->get_id(),
            'order_status' => $order->get_status(),
            'failure_reason' => isset($event_data['failure_reason']) ? $event_data['failure_reason'] : null,
        ));

        // 更新订单状态为失败
        $order->update_status('failed', __('StablePay 支付失败', 'stablepay-woocommerce'));

        $this->logger->info('订单支付失败', array(
            'order_id' => $order->get_id(),
            'new_status' => 'failed',
        ));
    }

    /**
     * 处理支付超时事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_payment_expired($order, $event_data) {
        $this->logger->debug('处理支付超时事件', array(
            'order_id' => $order->get_id(),
            'order_status' => $order->get_status(),
        ));

        // 更新订单状态为已取消
        $order->update_status('cancelled', __('StablePay 支付超时', 'stablepay-woocommerce'));

        $this->logger->info('订单支付超时', array(
            'order_id' => $order->get_id(),
            'new_status' => 'cancelled',
        ));
    }

    /**
     * 处理支付确认中事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_payment_pending($order, $event_data) {
        $this->logger->debug('处理支付确认中事件', array(
            'order_id' => $order->get_id(),
            'order_status' => $order->get_status(),
        ));

        // 根据配置决定是否更新订单状态
        $gateway = WC()->payment_gateways()->payment_gateways()['stablepay'];
        $pending_status = $gateway->get_option('pending_status', 'pending');

        $this->logger->debug('检查 pending 状态配置', array(
            'order_id' => $order->get_id(),
            'pending_status_config' => $pending_status,
        ));

        if ($pending_status === 'on-hold') {
            $order->update_status('on-hold', __('StablePay 支付确认中', 'stablepay-woocommerce'));
            $this->logger->info('订单状态更新为等待确认', array(
                'order_id' => $order->get_id(),
                'new_status' => 'on-hold',
            ));
        } else {
            $this->logger->info('订单支付确认中，保持当前状态', array(
                'order_id' => $order->get_id(),
                'current_status' => $order->get_status(),
            ));
        }
    }

    /**
     * 处理退款成功事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_refund_succeeded($order, $event_data) {
        $refund_id = isset($event_data['refund_id']) ? $event_data['refund_id'] : '';
        $amount = isset($event_data['refund_amount']) ? (float)$event_data['refund_amount'] : 0;
        $tx_hash = isset($event_data['transaction_hash']) ? $event_data['transaction_hash'] : '';

        $this->logger->debug('处理退款成功事件', array(
            'order_id' => $order->get_id(),
            'refund_id' => $refund_id,
            'amount' => $amount,
            'transaction_hash' => $tx_hash,
        ));

        // 查找对应的退款记录
        $refunds = $order->get_refunds();
        $this->logger->debug('查找退款记录', array(
            'order_id' => $order->get_id(),
            'refund_count' => count($refunds),
        ));

        $found = false;
        foreach ($refunds as $refund) {
            $stored_refund_id = $refund->get_meta('_stablepay_refund_id');
            if ($stored_refund_id === $refund_id) {
                $this->logger->debug('找到匹配的退款记录', array(
                    'order_id' => $order->get_id(),
                    'refund_id' => $refund_id,
                    'wc_refund_id' => $refund->get_id(),
                ));

                // 更新退款元数据
                $refund->update_meta_data('_stablepay_refund_status', 'succeeded');
                $refund->update_meta_data('_stablepay_refund_tx_hash', $tx_hash);
                $refund->update_meta_data('_stablepay_refund_processed_at', time());
                $refund->save();

                $found = true;
                break;
            }
        }

        // 清除 pending 退款状态
        StablePay_Refund_Manager::clear_pending_refund($order, $refund_id);

        // 添加订单备注
        $note = sprintf(
            __('StablePay 退款成功。退款金额：%s', 'stablepay-woocommerce'),
            wc_price($amount)
        );
        if (!empty($tx_hash)) {
            $note .= sprintf(__('，交易哈希：%s', 'stablepay-woocommerce'), $tx_hash);
        }
        $order->add_order_note($note);

        // 检查是否需要更新订单状态为 refunded（全额退款）
        StablePay_Refund_Manager::maybe_update_order_to_refunded($order);

        $this->logger->info('退款成功处理完成', array(
            'order_id' => $order->get_id(),
            'refund_id' => $refund_id,
            'amount' => $amount,
            'tx_hash' => $tx_hash,
            'refund_record_found' => $found,
        ));

        if (!$found) {
            $this->logger->warning('未找到对应的退款记录，但已清除 pending 状态', array(
                'order_id' => $order->get_id(),
                'refund_id' => $refund_id,
                'existing_refunds' => array_map(function($r) {
                    return array(
                        'id' => $r->get_id(),
                        'stablepay_refund_id' => $r->get_meta('_stablepay_refund_id'),
                    );
                }, $refunds),
            ));
        }
    }

    /**
     * 处理退款失败事件
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function handle_refund_failed($order, $event_data) {
        $refund_id = isset($event_data['refund_id']) ? $event_data['refund_id'] : '';
        $failure_reason = isset($event_data['failure_reason']) ? $event_data['failure_reason'] : __('未知原因', 'stablepay-woocommerce');

        $this->logger->debug('处理退款失败事件', array(
            'order_id' => $order->get_id(),
            'refund_id' => $refund_id,
            'failure_reason' => $failure_reason,
        ));

        // 查找对应的退款记录
        $refunds = $order->get_refunds();
        $refund_to_delete = null;
        $refund_amount = 0;

        foreach ($refunds as $refund) {
            $stored_refund_id = $refund->get_meta('_stablepay_refund_id');
            if ($stored_refund_id === $refund_id) {
                $this->logger->debug('找到匹配的退款记录，准备删除', array(
                    'order_id' => $order->get_id(),
                    'refund_id' => $refund_id,
                    'wc_refund_id' => $refund->get_id(),
                ));

                $refund_to_delete = $refund;
                $refund_amount = abs($refund->get_amount());
                break;
            }
        }

        // 清除 pending 退款状态
        StablePay_Refund_Manager::clear_pending_refund($order, $refund_id);

        // 添加订单备注
        $order->add_order_note(sprintf(
            __('StablePay 退款失败。退款 ID：%s，原因：%s', 'stablepay-woocommerce'),
            $refund_id,
            $failure_reason
        ));

        // 删除退款记录（恢复订单金额）
        if ($refund_to_delete) {
            $wc_refund_id = $refund_to_delete->get_id();

            // 删除退款记录
            // 注意：wp_delete_post 会删除退款记录，WooCommerce 会自动恢复订单的已退款金额
            $deleted = wp_delete_post($wc_refund_id, true);

            if ($deleted) {
                $this->logger->info('退款记录已删除，订单金额已恢复', array(
                    'order_id' => $order->get_id(),
                    'refund_id' => $refund_id,
                    'wc_refund_id' => $wc_refund_id,
                    'refund_amount' => $refund_amount,
                ));

                // 添加订单备注说明退款记录已删除
                $order->add_order_note(sprintf(
                    __('由于退款失败，已撤销退款记录（退款金额 %s 已恢复）', 'stablepay-woocommerce'),
                    wc_price($refund_amount)
                ));
            } else {
                $this->logger->error('删除退款记录失败', array(
                    'order_id' => $order->get_id(),
                    'refund_id' => $refund_id,
                    'wc_refund_id' => $wc_refund_id,
                ));
            }
        } else {
            $this->logger->warning('退款失败事件：未找到对应的退款记录', array(
                'order_id' => $order->get_id(),
                'refund_id' => $refund_id,
                'existing_refunds' => array_map(function($r) {
                    return array(
                        'id' => $r->get_id(),
                        'stablepay_refund_id' => $r->get_meta('_stablepay_refund_id'),
                    );
                }, $refunds),
            ));
        }

        $this->logger->error('退款失败处理完成', array(
            'order_id' => $order->get_id(),
            'refund_id' => $refund_id,
            'failure_reason' => $failure_reason,
            'refund_deleted' => $refund_to_delete !== null,
        ));
    }

    /**
     * 保存交易信息到订单元数据
     *
     * @param WC_Order $order 订单对象
     * @param array $event_data 事件数据
     */
    private function save_transaction_info($order, $event_data) {
        $this->logger->debug('保存交易信息到订单', array(
            'order_id' => $order->get_id(),
            'session_id' => $event_data['session_id'],
            'has_transaction' => isset($event_data['transaction']),
        ));

        // 保存支付会话 ID
        $order->update_meta_data('_stablepay_session_id', $event_data['session_id']);

        // 保存订单原始币种
        if (isset($event_data['currency'])) {
            $order->update_meta_data('_stablepay_currency', $event_data['currency']);
        }

        // 保存实际支付的加密货币类型（用于退款）
        if (isset($event_data['payment_currency'])) {
            $order->update_meta_data('_stablepay_paid_currency', $event_data['payment_currency']);
        }

        // 保存交易信息
        if (isset($event_data['transaction'])) {
            $tx = $event_data['transaction'];

            $this->logger->debug('保存区块链交易详情', array(
                'order_id' => $order->get_id(),
                'tx_hash' => isset($tx['tx_hash']) ? $tx['tx_hash'] : null,
                'from_address' => isset($tx['from_address']) ? $tx['from_address'] : null,
                'amount_received' => isset($tx['amount_received']) ? $tx['amount_received'] : null,
                'block_number' => isset($tx['block_number']) ? $tx['block_number'] : null,
                'confirmations' => isset($tx['confirmations']) ? $tx['confirmations'] : null,
            ));

            if (isset($tx['tx_hash'])) {
                $order->update_meta_data('_stablepay_tx_hash', $tx['tx_hash']);
            }
            if (isset($tx['from_address'])) {
                $order->update_meta_data('_stablepay_from_address', $tx['from_address']);
            }
            if (isset($tx['amount_received'])) {
                $order->update_meta_data('_stablepay_amount_received', $tx['amount_received']);
            }
            if (isset($tx['block_number'])) {
                $order->update_meta_data('_stablepay_block_number', $tx['block_number']);
            }
            if (isset($tx['confirmations'])) {
                $order->update_meta_data('_stablepay_confirmations', $tx['confirmations']);
            }
            if (isset($tx['confirmed_at'])) {
                $order->update_meta_data('_stablepay_paid_at', $tx['confirmed_at']);
            }
        }

        $order->save();
        $this->logger->debug('交易信息保存完成', array('order_id' => $order->get_id()));
    }

    /**
     * 检查事件是否已处理
     *
     * @param string $event_id 事件 ID
     * @return bool 是否已处理
     */
    private function is_event_processed($event_id) {
        if (empty($event_id)) {
            return false;
        }

        $processed_events = get_transient('stablepay_processed_events');
        if (!is_array($processed_events)) {
            $processed_events = array();
        }

        return isset($processed_events[$event_id]);
    }

    /**
     * 标记事件已处理
     *
     * @param string $event_id 事件 ID
     */
    private function mark_event_processed($event_id) {
        if (empty($event_id)) {
            return;
        }

        $processed_events = get_transient('stablepay_processed_events');
        if (!is_array($processed_events)) {
            $processed_events = array();
        }

        $processed_events[$event_id] = time();

        // 清理7天前的记录
        $seven_days_ago = time() - (7 * 24 * 60 * 60);
        foreach ($processed_events as $id => $timestamp) {
            if ($timestamp < $seven_days_ago) {
                unset($processed_events[$id]);
            }
        }

        // 保存24小时
        set_transient('stablepay_processed_events', $processed_events, 24 * 60 * 60);
    }
}
