import {Context} from "koa";
import * as crypto from 'crypto';
import {ChannelHandler, LoginResult, PaymentResult,} from "../interfaces/ChannelHandler";
import {ChannelConfig} from "../../config/channelConfig";
import {ChannelConfigManager} from "../../utils/ChannelConfigManager";
import {formatDate, getServerList} from "../../utils/common";
import {Account, MINI_APP_PRIVATE_KEY, MINI_APP_GAME_ID, DOUYIN_MINI_APP_PRIVATE_KEY, DOUYIN_MINI_APP_GAME_ID, MINI_APP_DOMAIN, MINI_APP_API_KEY, MINI_APP_STAT_API_KEY} from "../../config/thirdParams";
import {PaymentHelper} from "../../utils/PaymentHelper";

import Msg from "../../utils/msg";
import axios from "axios";
import { insertMailToPlayer } from "../../mongo/mongodb";

const Order = require("../../model/OrderModel");
const CryptoJS = require("crypto-js");
const logger = require("../../utils/log");

export class MiniappChannelHandler implements ChannelHandler {
    /**
     * 根据platform参数获取渠道11的配置
     * @param platform 平台参数：miniapp（小程序）或 ttminiapp（抖音小程序）
     * @returns 渠道配置对象
     */
    private getChannel11Config(platform: string): ChannelConfig {
        const baseConfig = ChannelConfigManager.getConfig(11);
        if (!baseConfig) {
            throw new Error("渠道11配置不存在");
        }

        // 如果是抖音小程序，使用抖音的参数
        if (platform === 'ttminiapp') {
            return {
                ...baseConfig,
                platform: 'ttminiapp',
                name: '抖音小程序',
                paymentConfig: {
                    ...baseConfig.paymentConfig,
                    signKey: DOUYIN_MINI_APP_PRIVATE_KEY,
                    gameId: DOUYIN_MINI_APP_GAME_ID,
                },
                loginConfig: {
                    ...baseConfig.loginConfig,
                    apiKey: DOUYIN_MINI_APP_PRIVATE_KEY, // 抖音使用privateKey作为apiKey
                }
            };
        } else {
            // 默认使用小程序的参数
            return {
                ...baseConfig,
                platform: 'miniapp',
                name: '小程序',
                paymentConfig: {
                    ...baseConfig.paymentConfig,
                    signKey: MINI_APP_PRIVATE_KEY,
                    gameId: MINI_APP_GAME_ID,
                }
            };
        }
    }
    /**
     * 获取HTTPS代理配置
     * @returns HTTPS代理配置
     */
    private getHttpsAgent() {
        const https = require('https');
        return new https.Agent({
            rejectUnauthorized: false,
            secureProtocol: 'TLSv1_2_method',
            timeout: 10000
        });
    }

    /**
     * 获取通用请求头
     * @returns 请求头配置
     */
    private getCommonHeaders() {
        return {
            'User-Agent': 'Mozilla/5.0 (compatible; WebServer/1.0)',
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        };
    }

    /**
     * 统一登录鉴权（支持小程序和iOS）
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            const platform = data.platform; // 平台参数：ios、Android、miniapp、ttminiapp、h5

            logger.info("统一登录请求", { platform, data });

            // 根据平台选择不同的登录方式
            if (platform === 'ios') {
                return await this.handleIOSLogin(data, config);
            } else {
                // 对于渠道11，根据platform参数动态获取配置
                let actualConfig = config;
                if (config.channelId === 11) {
                    actualConfig = this.getChannel11Config(platform || 'miniapp');
                    logger.info("渠道11动态配置", { platform, config: actualConfig });
                }
                // 默认使用小程序登录方式
                return await this.handleMiniappLogin(data, actualConfig);
            }
        } catch (error) {
            logger.error('统一登录错误:', error);
            return {
                code: -1,
                msg: error.message || "登录验证失败",
                data: null,
            };
        }
    }

    /**
     * 小程序登录鉴权
     * @param data 请求数据
     * @param config 渠道配置
     */
    private async handleMiniappLogin(data: any, config: ChannelConfig): Promise<LoginResult> {
        try {
            const token = data.token;

            if (!token) {
                return {
                    code: -1,
                    msg: "缺少token参数",
                    data: null
                };
            }

            const loginUrl = `https://wxlogin.${config.paymentConfig.apiUrl}/wxlogin?cmd=checkUserToken&token=${token}`;
            logger.info("小程序登录请求", {token, loginUrl});

            const wxLogin = await axios.get(loginUrl, {
                httpsAgent: this.getHttpsAgent(),
                headers: this.getCommonHeaders()
            });
            logger.info("小程序登录响应", {data: wxLogin.data});
            if (!wxLogin.data || Object.keys(wxLogin.data).length === 0) {
                return {
                    code: -1,
                    msg: "登录验证失败",
                    data: null,
                };
            }
            return {
                code: 0,
                msg: "success",
                data: wxLogin.data,
            };
        } catch (error) {
            logger.error('小程序登录错误:', error);
            return {
                code: -1,
                msg: error.message || "登录验证失败",
                data: null,
            };
        }
    }

    /**
     * iOS登录鉴权
     * @param data 请求数据
     * @param config 渠道配置
     */
    private async handleIOSLogin(data: any, config: ChannelConfig): Promise<LoginResult> {
        try {
            const { token } = data;
            const gameid = '1550';
            // 验证必要参数
            if (!token) {
                logger.error("iOS登录鉴权失败 - 缺少token参数");
                return {
                    code: -1,
                    msg: "缺少必要参数: token",
                    data: null
                };
            }

            logger.info("iOS登录鉴权请求参数:", { token,gameid });

            // 调用第三方鉴权API
            const apiUrl = `https://api.11h5.com/login?cmd=checkUserToken&userToken=${encodeURIComponent(token)}&gameid=${gameid}`;

            logger.info("调用iOS鉴权API:", { url: apiUrl });

            const response = await axios.get(apiUrl, {
                timeout: 10000,
                headers: this.getCommonHeaders(),
                httpsAgent: this.getHttpsAgent()
            });

            logger.info("iOS鉴权API响应:", response.data);

            // 根据错误码判断成功与否
            const responseData = response.data;

            if (responseData.error === 0) {
                // 成功：error = 0
                logger.info("iOS登录鉴权成功:", {
                    uid: responseData.uid,
                    nickname: responseData.nickname,
                    usertype: responseData.usertype
                });

                return {
                    code: 0,
                    msg: "登录成功",
                    data: {
                        uid: responseData.uid,
                        nickname: responseData.nickname,
                        headimgurl: responseData.headimgurl,
                        sex: responseData.sex,
                        focus: responseData.focus,
                        usertype: responseData.usertype
                    }
                };
            } else if (responseData.error === 401) {
                // 参数有误
                logger.error("iOS登录鉴权失败 - 参数有误:", responseData);
                return {
                    code: -1,
                    msg: "参数有误，请检查接口所需参数是否都已经填写正确",
                    data: null
                };
            } else if (responseData.error === 403) {
                // token验证失败
                logger.error("iOS登录鉴权失败 - token验证失败:", responseData);
                return {
                    code: -1,
                    msg: "token验证失败，同一个userToken只能验证一次，可通过刷新游戏重新获取",
                    data: null
                };
            } else {
                // 其他错误
                logger.error("iOS登录鉴权失败 - 未知错误:", responseData);
                return {
                    code: -1,
                    msg: "鉴权失败，请稍后重试",
                    data: null
                };
            }

        } catch (error) {
            logger.error("iOS登录鉴权出错:", error);
            return {
                code: -1,
                msg: "登录鉴权失败",
                data: null
            };
        }
    }

    /**
     * 统一支付回调处理
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
        try {
            // 获取请求参数 - 支持GET和POST请求
            const params = ctx.request.query as any;

            const platform = params.platform || 'miniapp'; // 平台参数：ios、Android、miniapp、h5，默认为miniapp

            logger.info("统一支付回调请求", { platform, url: ctx.href, params: params });

            // 根据平台选择不同的支付处理方式和配置
            if (platform === 'ios') {
                // iOS使用渠道12的配置
                const iosConfig = ChannelConfigManager.getConfig(12);
                if (!iosConfig) {
                    logger.error("未找到iOS渠道配置");
                    return {
                        code: -1,
                        msg: "iOS渠道配置不存在",
                        data: null
                    };
                }
                return await this.handleIOSPayment(params, iosConfig);
            } else {
                // 默认使用小程序支付方式和渠道11的配置
                const baseConfig = ChannelConfigManager.getConfig(11);
                if (!baseConfig) {
                    logger.error("未找到小程序渠道配置");
                    return {
                        code: -1,
                        msg: "小程序渠道配置不存在",
                        data: null
                    };
                }
                // 根据platform参数动态获取配置
                const miniappConfig = this.getChannel11Config(platform || 'miniapp');
                logger.info("渠道11支付动态配置", { platform, config: miniappConfig });
                return await this.handleMiniappPayment(params, miniappConfig);
            }
        } catch (error) {
            logger.error('统一支付处理错误:', error);
            return {
                code: -1,
                msg: error.message || "支付处理失败",
                data: null
            };
        }
    }

    /**
     * iOS支付回调处理
     * @param params 请求参数
     * @param config 渠道配置
     */
    private async handleIOSPayment(params: any, config: ChannelConfig): Promise<PaymentResult> {
        try {
            // 验证必要参数
            const requiredParams = ['openid', 'rmb', 'reqid', 'trans_id', 'product_id', 'notify_id', 'sign','txid'];
            for (const param of requiredParams) {
                if (!params[param]) {
                    logger.error(`缺少必要参数: ${param}`);
                    return {
                        code: -1,
                        msg: `缺少必要参数: ${param}`,
                        data: null
                    };
                }
            }

            // 验证签名（使用iOS的签名算法）
            const isValidSignature = this.verifyPaymentSignature(params, config);
            if (!isValidSignature) {
                logger.error("iOS支付签名验证失败", {
                    received: params.sign,
                    params: params
                });
                return {
                    code: -1,
                    msg: "签名验证失败",
                    data: null
                };
            }

            // 订单校验
            const orderCheckResult = await this.verifyOrderInternal(params.notify_id, config.paymentConfig.gameId, config);
            if (!orderCheckResult.success) {
                logger.error(`订单${params.reqid}校验失败: ${orderCheckResult.message}`);
                return {
                    code: -1,
                    msg: `订单校验失败: ${orderCheckResult.message}`,
                    data: null
                };
            }
            const orderId = params.txid;//订单号
            const out_trade_no = params.trans_id;//平台订单号
            const validation = await PaymentHelper.validateOrder(orderId);
            if (!validation.valid) {
                return {
                    code: validation.message?.includes("重复发货") ? 1 : 0,
                    msg: validation.message || "订单验证失败"
                };
            }
            const orderInfo = validation.orderInfo;

            logger.info("IOS订单校验成功，开始处理支付发货逻辑");
            const result = await PaymentHelper.deliverOrder(
                orderInfo,
                "127.0.0.1", // 使用默认IP地址，因为iOS支付没有客户端IP
                validation.url,
                out_trade_no
            );
            // 处理支付成功逻辑
            logger.info(`iOS支付成功 - 用户: ${params.openid}, 金额: ${params.rmb}, 订单: ${out_trade_no}, 发货结果:`, result);
            return result;

        } catch (error) {
            logger.error("iOS支付处理出错:", error);
            return {
                code: -1,
                msg: "iOS支付处理失败",
                data: null
            };
        }
    }

    /**
     * 小程序支付回调处理
     * @param params 请求参数
     * @param config 渠道配置
     */
    private async handleMiniappPayment(params: any, config: ChannelConfig): Promise<PaymentResult> {
        try {

            // 验证必要参数
            const requiredParams = ['uid', 'rmb', 'reqid', 'trans_id', 'product_id', 'notify_id', 'sign'];
            for (const param of requiredParams) {
                if (!params[param]) {
                    logger.error(`缺少必要参数: ${param}`);
                    return {
                        code: -1,
                        msg: `缺少必要参数: ${param}`,
                        data: null
                    };
                }
            }

            // 验证签名 - 排除platform和channel_id参数
            const parameters = Object.keys(params)
                .filter(key => key !== 'sign')
                .map(key => `${key}=${params[key]}`);

            const expectedSignature = this.generateSignature(parameters, config.paymentConfig.signKey!);
            if (params.sign !== expectedSignature) {
                logger.error("小程序支付签名验证失败", {
                    received: params.sign,
                    expected: expectedSignature
                });
                return {
                    code: -1,
                    msg: "签名验证失败",
                    data: null
                };
            }
            const orderId = params.txid;//订单号
            const out_trade_no = params.trans_id;//平台订单号
            // 订单校验 - 验证支付是否成功
            const orderCheckResult = await this.wxOrderCheck(params.notify_id, config);
            if (!orderCheckResult.success) {
                logger.error(`订单${orderId}校验失败: ${orderCheckResult.message}`);
                return {
                    code: -1,
                    msg: `订单校验失败: ${orderCheckResult.message}`,
                    data: null
                };
            }

            const validation = await PaymentHelper.validateOrder(orderId);
            if (!validation.valid) {
                return {
                    code: validation.message?.includes("重复发货") ? 1 : 0,
                    msg: validation.message || "订单验证失败"
                };
            }
            const orderInfo = validation.orderInfo;
            // 发货处理
            logger.info(`小程序支付订单${orderId}通知游戏发货开始`);
            const result = await PaymentHelper.deliverOrder(
                orderInfo,
                "127.0.0.1", // 使用默认IP地址，因为小程序支付没有客户端IP
                validation.url,
                out_trade_no
            );
            // 处理支付成功逻辑
            logger.info(`小程序支付成功 - 用户: ${params.uid}, 金额: ${params.rmb}, 订单: ${out_trade_no}, 发货结果:`, result);
            return result;
        } catch (error) {
            logger.error("小程序支付处理出错:", error);
            return {
                code: -1,
                msg: "支付处理失败",
                data: null
            };
        }
    }

    /**
     * 订单校验 - 验证支付是否成功
     * @param notifyId 平台通知ID
     * @param config 渠道配置
     * @returns 校验结果
     */
    async wxOrderCheck(notifyId: string, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
        try {
            // 构建验证参数
            const parameters = [
                `gameid=${config.paymentConfig.gameId}`,
                `notify_id=${notifyId}`
            ];

            // 生成签名
            const signature = this.generateSignature(parameters, config.paymentConfig.signKey!);

            // 构建验证URL
            const verifyUrl = `https://login.${config.paymentConfig.apiUrl}/pay/paygate/verify.php?gameid=${config.paymentConfig.gameId}&notify_id=${notifyId}&sign=${signature}`;

            logger.info("订单校验请求", {notifyId, verifyUrl});

            // 调用平台验证接口
            const response = await axios.get(verifyUrl, {
                httpsAgent: this.getHttpsAgent(),
                headers: {
                    ...this.getCommonHeaders(),
                    'Accept': 'text/plain'
                }
            });

            logger.info("订单校验响应", {notifyId, response: response.data});

            // 检查返回结果
            if (response.data === "SUCCESS") {
                return {
                    success: true,
                    message: "订单支付成功"
                };
            } else {
                return {
                    success: false,
                    message: "订单支付失败或无效"
                };
            }

        } catch (error) {
            logger.error("订单校验出错:", {notifyId, error: error.message});
            return {
                success: false,
                message: "订单校验失败"
            };
        }
    }

    /**
     * 执行小程序内容安全审核
     * @param params 审核参数
     * @param config 渠道配置
     * @returns 审核结果
     */
    private async performMiniappContentSecurityCheck(params: {
        uid: string;
        content: string;
        scene?: string;
        nickname?: string;
        title?: string;
        usersign?: string;
    }, config: ChannelConfig): Promise<{
        success: boolean;
        error?: number;
        errmsg?: string;
        result?: any;
        trace_id?: string;
        detail?: any;
    }> {
        try {
            const timestamp = Math.floor(Date.now() / 1000);
            const nonce = Math.floor(Math.random() * 1000000);

            // 使用小程序配置
            let actualConfig = config;
            if (config.channelId === 11) {
                actualConfig = this.getChannel11Config('miniapp');
            }

            // 生成签名
            const signature = this.generateContentSecuritySignature({ timestamp, nonce }, actualConfig);
            if (!signature) {
                return {
                    success: false,
                    error: -1,
                    errmsg: "签名生成失败"
                };
            }

            // 构建请求参数
            const requestData = {
                uid: params.uid,
                gameid: actualConfig.paymentConfig.gameId,
                signature: signature,
                timestamp: timestamp,
                nonce: nonce,
                scene: params.scene || '1',
                content: params.content,
                nickname: params.nickname || '',
                title: params.title || '',
                usersign: params.usersign || ''
            };

            // 调用小程序内容安全API
            const apiUrl = `https://api.${actualConfig.paymentConfig.apiUrl}/mpcommon/?cmd=wxaMsgSecCheck`;
            logger.info("调用小程序内容安全API:", { 
                url: apiUrl, 
                content: params.content.substring(0, 50) + '...' 
            });

            const response = await axios.post(apiUrl, requestData, {
                httpsAgent: this.getHttpsAgent(),
                headers: this.getCommonHeaders()
            });

            logger.info("小程序内容安全API响应:", response.data);

            // 处理响应结果
            if (response.data && response.data.error === 0) {
                return {
                    success: true,
                    error: 0,
                    result: response.data.result,
                    trace_id: response.data.trace_id,
                    detail: response.data.detail
                };
            } else {
                return {
                    success: false,
                    error: response.data?.error || -1,
                    errmsg: response.data?.errmsg || "内容安全检测失败"
                };
            }
        } catch (error) {
            logger.error("小程序内容安全审核出错:", error);
            return {
                success: false,
                error: -1,
                errmsg: "内容安全审核失败"
            };
        }
    }

    /**
     * 执行抖音内容安全审核
     * @param params 审核参数
     * @param config 渠道配置
     * @returns 审核结果
     */
    private async performByteDanceContentSecurityCheck(params: {
        uid: string;
        content: string;
        scene?: string;
        nickname?: string;
        title?: string;
        usersign?: string;
    }, config: ChannelConfig): Promise<{
        success: boolean;
        error?: number;
        errmsg?: string;
        result?: any;
        trace_id?: string;
        detail?: any;
    }> {
        try {
            const timestamp = Math.floor(Date.now() / 1000);
            const nonce = Math.floor(Math.random() * 1000000);

            // 使用抖音小程序配置
            let actualConfig = config;
            if (config.channelId === 11) {
                actualConfig = this.getChannel11Config('ttminiapp');
            }

            // 生成签名
            const signature = this.generateContentSecuritySignature({ timestamp, nonce }, actualConfig);
            if (!signature) {
                return {
                    success: false,
                    error: -1,
                    errmsg: "签名生成失败"
                };
            }

            // 构建请求参数
            const requestData = {
                uid: params.uid,
                gameid: actualConfig.paymentConfig.gameId,
                signature: signature,
                timestamp: timestamp,
                nonce: nonce,
                scene: params.scene || '1',
                content: params.content,
                nickname: params.nickname || '',
                title: params.title || '',
                usersign: params.usersign || ''
            };

            // 调用抖音内容安全API
            const apiUrl = `https://api.${actualConfig.paymentConfig.apiUrl}/mpcommon/?cmd=byteDanceMsgSecCheck`;
            logger.info("调用抖音内容安全API:", { 
                url: apiUrl, 
                content: params.content.substring(0, 50) + '...' 
            });

            const response = await axios.post(apiUrl, requestData, {
                httpsAgent: this.getHttpsAgent(),
                headers: this.getCommonHeaders()
            });

            logger.info("抖音内容安全API响应:", response.data);

            // 处理抖音响应结果（抖音返回结构：{error: 0, msg: "ok", data: {}}）
            // error: 0 代表通过，其他错误码代表检测不通过
            if (response.data && response.data.error === 0) {
                // 抖音API返回通过，返回统一的格式
                return {
                    success: true,
                    error: 0,
                    result: {
                        suggest: 'pass' // 抖音返回error=0表示通过
                    }
                };
            } else {
                // 抖音API返回不通过
                return {
                    success: false,
                    error: response.data?.error || -1,
                    errmsg: response.data?.msg || response.data?.errmsg || "内容安全检测失败"
                };
            }
        } catch (error) {
            logger.error("抖音内容安全审核出错:", error);
            return {
                success: false,
                error: -1,
                errmsg: "内容安全审核失败"
            };
        }
    }

    /**
     * 内容安全审核接口
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async contentSecurityCheck(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            // 支持从GET query参数或POST body中获取platform参数
            const platform = ctx.request.query.platform || data.platform || 'miniapp';
            logger.info("内容安全审核请求参数:", { ...data, platform });

            // 验证必要参数
            const requiredParams = ['uid', 'scene', 'content'];
            for (const param of requiredParams) {
                if (!data[param]) {
                    logger.error(`缺少必要参数: ${param}`);
                    return {
                        code: -1,
                        msg: `缺少必要参数: ${param}`,
                        data: null
                    };
                }
            }

            // 根据platform调用对应的内容安全审核方法
            const checkResult = platform === 'ttminiapp' 
                ? await this.performByteDanceContentSecurityCheck({
                    uid: data.uid,
                    content: data.content,
                    scene: data.scene,
                    nickname: data.nickname,
                    title: data.title,
                    usersign: data.usersign
                }, config)
                : await this.performMiniappContentSecurityCheck({
                    uid: data.uid,
                    content: data.content,
                    scene: data.scene,
                    nickname: data.nickname,
                    title: data.title,
                    usersign: data.usersign
                }, config);

            // 处理审核结果
            if (checkResult.success && checkResult.result) {
                return {
                    code: 0,
                    msg: "success",
                    data: {
                        suggest: checkResult.result.suggest, // pass/review/reject
                        label: checkResult.result.label,
                        trace_id: checkResult.trace_id,
                        detail: checkResult.detail
                    }
                };
            } else {
                return {
                    code: -1,
                    msg: checkResult.errmsg || "内容安全检测失败",
                    data: null
                };
            }
        } catch (error) {
            logger.error("内容安全审核出错:", error);
            return {
                code: -1,
                msg: "内容安全审核失败",
                data: null
            };
        }
    }

    /**
     * 内部内容安全检查方法（用于角色名称等场景）
     * @param content 待检查内容
     * @param uid 用户ID
     * @param config 渠道配置
     * @param scene 场景类型，默认为'1'（角色名称）
     * @param platform 平台类型：miniapp（小程序）或 ttminiapp（抖音小程序），默认为 miniapp
     * @returns 检查结果，suggest: pass/review/reject/risky
     */
    private async checkContentSecurity(
        content: string, 
        uid: string, 
        config: ChannelConfig,
        scene: string = '1',
        platform: string = 'miniapp'
    ): Promise<{ success: boolean; suggest?: string; message: string }> {
        // 根据platform调用对应的内容安全审核方法
        const checkResult = platform === 'ttminiapp'
            ? await this.performByteDanceContentSecurityCheck({
                uid: uid,
                content: content,
                scene: scene
            }, config)
            : await this.performMiniappContentSecurityCheck({
                uid: uid,
                content: content,
                scene: scene
            }, config);

        console.log("checkResult:", checkResult);
        // 处理审核结果
        if (checkResult.success && checkResult.result) {
            const suggest = checkResult.result.suggest; // pass/review/reject/risky
            
            // 拒绝状态：reject 和 risky 都应该拒绝
            if (suggest === 'reject' || suggest === 'risky') {
                logger.warn("内容安全审核未通过:", { 
                    content: content.substring(0, 20) + '...', 
                    uid, 
                    suggest,
                    detail: checkResult.detail
                });
                return {
                    success: false,
                    suggest: suggest,
                    message: suggest === 'risky' ? "内容存在风险，无法使用" : "内容包含敏感信息，无法使用"
                };
            } else if (suggest === 'review') {
                // review状态可以选择允许或拒绝，这里选择允许但记录日志
                logger.warn("内容需要人工审核:", { 
                    content: content.substring(0, 20) + '...', 
                    uid, 
                    suggest,
                    detail: checkResult.detail
                });
                return {
                    success: true,
                    suggest: suggest,
                    message: "内容通过审核"
                };
            } else if (suggest === 'pass') {
                // pass状态，允许通过
                return {
                    success: true,
                    suggest: suggest,
                    message: "内容通过审核"
                };
            } else {
                // 未知状态，记录日志并允许通过（容错处理）
                logger.warn("内容安全审核返回未知状态:", { 
                    content: content.substring(0, 20) + '...', 
                    uid, 
                    suggest,
                    detail: checkResult.detail
                });
                return {
                    success: true,
                    suggest: suggest,
                    message: "内容通过审核"
                };
            }
        } else {
            logger.error("内容安全审核API返回错误:", checkResult.errmsg);
            // API错误时，为了不影响用户体验，可以选择允许通过或拒绝
            // 这里选择允许通过，但记录错误日志
            return {
                success: false, 
                suggest: "reject",
                message: "内容安全审核失败，已拒绝"
            };
        }
    }

    /**
     * 角色名称修改上报
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async editUserRoleInfo(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            // 支持从GET query参数或POST body中获取platform参数
            const platform = ctx.request.query.platform || data.platform || 'miniapp';
            logger.info("角色名称修改上报请求参数:", { ...data, platform });
            
            // 验证必要参数
            const requiredParams = ['openId', 'serverid', 'playerName'];
            for (const param of requiredParams) {
                if (!data[param]) {
                    logger.error(`缺少必要参数: ${param}`);
                    return {
                        code: -1,
                        msg: `缺少必要参数: ${param}`,
                        data: null
                    };
                }
            }
            data['time'] = Math.floor(Date.now() / 1000); // 添加时间戳参数
            data['gameid'] = config.paymentConfig.gameId; // 添加游戏ID参数

            // 处理playerName的各种编码格式
            let decodedPlayerName = data.playerName;
            try {
                // 检查是否是URL编码格式
                if (data.playerName.includes('%')) {
                    decodedPlayerName = decodeURIComponent(data.playerName);
                    console.log("playerName URL decoded from:", data.playerName);
                    console.log("playerName URL decoded to:", decodedPlayerName);
                }
                // 检查是否是Unicode转义序列格式
                else if (data.playerName.includes('\\u')) {
                    decodedPlayerName = JSON.parse('"' + data.playerName + '"');
                    console.log("playerName Unicode decoded from:", data.playerName);
                    console.log("playerName Unicode decoded to:", decodedPlayerName);
                } else {
                    console.log("playerName is not encoded:", data.playerName);
                }
            } catch (error) {
                console.log("playerName decode error, using original:", error.message);
                decodedPlayerName = data.playerName;
            }

            // 更新data中的playerName为解码后的值
            data.playerName = decodedPlayerName;
            console.log("playerName for signature:", data.playerName);

            // 内容安全审核：验证角色名称是否包含敏感内容
            const securityCheck = await this.checkContentSecurity(decodedPlayerName, data.openId, config, '1', platform as string);
            if (!securityCheck.success) {
                logger.warn("角色名称内容安全审核未通过:", {
                    playerName: decodedPlayerName,
                    openId: data.openId,
                    suggest: securityCheck.suggest,
                    message: securityCheck.message
                });
                return {
                    code: -1,
                    msg: securityCheck.message || "角色名称包含敏感内容，无法使用",
                    data: null
                };
            }
            logger.info("角色名称内容安全审核通过:", {
                playerName: decodedPlayerName,
                openId: data.openId,
                suggest: securityCheck.suggest
            });

            //生成签名
            data['sign'] = this.generateRoleInfoSignature(data, config);

            // 构建请求参数 - 对playerName进行URL编码
            const encodedPlayerName = encodeURIComponent(data.playerName);
            console.log("playerName for request:", encodedPlayerName);

            // 手动构建URL查询字符串，避免对已编码参数进行二次编码
            const queryString = [
                `openId=${encodeURIComponent(data.openId)}`,
                `time=${encodeURIComponent(data.time)}`,
                `gameid=${encodeURIComponent(data.gameid)}`,
                `serverid=${encodeURIComponent(data.serverid)}`,
                `playerName=${encodedPlayerName}`, // 已经编码过的playerName，不再编码
                `sign=${encodeURIComponent(data.sign)}`
            ].join('&');

            // 调用角色信息修改API
            const apiUrl = `https://platform.${config.paymentConfig.apiUrl}/stat/api/?cmd=editUserRoleInfo&${queryString}`;
            logger.info("调用角色信息修改API:", {url: apiUrl});

            const response = await axios.get(apiUrl, {
                timeout: 10000,
                headers: {
                    'User-Agent': 'Mozilla/5.0 (compatible; WebServer/1.0)',
                    'Accept': 'application/json'
                },
                httpsAgent: this.getHttpsAgent()
            });
            logger.info("角色信息修改API响应:", response.data);

            // 处理响应结果
            if (response.data && response.data.error === 0) {
                return {
                    code: 0,
                    msg: "success",
                    data: null
                };
            } else {
                return {
                    code: 0,
                    msg: response.data?.errmsg || "角色信息修改失败",
                    data: null
                };
            }

        } catch (error) {
            logger.error("角色名称修改上报出错:", error);
            return {
                code: 0,
                msg: "角色信息修改失败",
                data: null
            };
        }
    }

    /**
     * 签名算法2验证
     * @param data 请求数据
     * @param config 渠道配置
     * @returns 验证结果
     */
    private verifySignatureAlgorithm2(data: any, config: ChannelConfig): boolean {
        try {
            // 固定密钥
            const secret = 'qka8qKcvRcGN1u0bLA8O';

            // 准备签名参数
            const signParams: any = {
                gameId: data.gameid || config.paymentConfig.gameId,
                openId: data.openId,
                playerName: encodeURIComponent(data.playerName), // 中文URL编码
                secret: secret,
                serverId: data.serverid,
                time: data.time
            };

            // 按字典排序参数名
            const sortedKeys = Object.keys(signParams).sort();

            // 构建签名字符串（去掉[]）
            const signString = sortedKeys.map(key => {
                return `${key}=${signParams[key]}`;
            }).join('');

            console.log("验证签名参数:", signParams);
            console.log("验证签名字符串:", signString);

            // 计算MD5签名
            const expectedSignature = CryptoJS.MD5(signString).toString();
            const actualSignature = data.sign;

            console.log("期望签名:", expectedSignature);
            console.log("实际签名:", actualSignature);

            return expectedSignature === actualSignature;
        } catch (error) {
            logger.error("签名算法2验证出错:", error);
            return false;
        }
    }

    /**
     * 生成角色信息修改签名（签名算法2）
     * @param params 签名参数
     * @param config 渠道配置
     * @returns 签名结果
     */
    generateRoleInfoSignature(params: any, config: ChannelConfig): string | null {
        try {
            // 固定密钥
            const secret = 'qka8qKcvRcGN1u0bLA8O';

            // 准备签名参数
            const signParams: any = {
                gameid: params.gameid || config.paymentConfig.gameId,
                openId: params.openId,
                playerName: encodeURIComponent(params.playerName), // 中文URL编码
                secret: secret,
                serverid: params.serverid,
                time: params.time
            };

            // 按字典排序参数名
            const sortedKeys = Object.keys(signParams).sort();

            // 构建签名字符串（去掉[]）
            const signString = sortedKeys.map(key => {
                return `${key}=${signParams[key]}`;
            }).join('');

            console.log("角色信息签名参数:", signParams);
            console.log("角色信息签名字符串:", signString);

            // 计算MD5签名
            const signature = CryptoJS.MD5(signString).toString();

            console.log("角色信息签名结果:", signature);

            return signature;
        } catch (error) {
            logger.error("生成角色信息修改签名出错:", error);
            return null;
        }
    }

    /**
     * 签名算法1验证
     * @param data 请求数据
     * @param config 渠道配置
     * @returns 验证结果
     */
    private verifySignatureAlgorithm1(data: any, config: ChannelConfig): boolean {
        return this.verifyCommonSignature(
            data,
            config.loginConfig?.apiKey || '',
            'signature',
            ['signature'],
            false // 内容安全签名不需要URL编码
        );
    }

    /**
     * 生成内容安全签名（签名算法1：SHA1）
     * 根据文档：将apiKey、timestamp、nonce按字典序排序后拼接，然后SHA1加密
     * @param params 签名参数（需包含timestamp和nonce）
     * @param config 渠道配置
     * @returns 签名结果
     */
    generateContentSecuritySignature(params: any, config: ChannelConfig): string | null {
        try {
            // 检查loginConfig和apiKey是否存在
            if (!config.loginConfig || !config.loginConfig.apiKey) {
                logger.error("生成内容安全签名出错: loginConfig或apiKey未配置", {
                    channelId: config.channelId,
                    hasLoginConfig: !!config.loginConfig,
                    hasApiKey: !!(config.loginConfig && config.loginConfig.apiKey)
                });
                return null;
            }

            const apiKey = config.loginConfig.apiKey;
            const timestamp = params.timestamp;
            const nonce = params.nonce;

            // 验证必要参数
            if (!timestamp || !nonce) {
                logger.error("生成内容安全签名出错: 缺少timestamp或nonce参数", {
                    hasTimestamp: !!timestamp,
                    hasNonce: !!nonce
                });
                return null;
            }

            // 签名算法1：将apiKey、timestamp、nonce按字典序排序后拼接，然后SHA1加密
            let arr = [apiKey, timestamp.toString(), nonce.toString()];
            arr.sort(); // 字典序排序
            let str = arr.join(''); // 拼接
            let signature = crypto.createHash('sha1').update(str).digest('hex'); // SHA1加密

            logger.info("内容安全签名生成详情（签名算法1）:", {
                apiKey: apiKey.substring(0, 10) + '...', // 只显示前10个字符，保护密钥
                timestamp,
                nonce,
                sortedArray: arr,
                signString: str.substring(0, 50) + '...', // 只显示前50个字符
                signature
            });

            return signature;
        } catch (error) {
            logger.error("生成内容安全签名出错:", error);
            return null;
        }
    }

    /**
     * 发货处理方法
     * @param orderInfo 订单信息
     * @param ip 客户端IP
     * @param url 游戏服务器URL
     * @param out_trade_no 外部交易号
     * @returns 发货结果
     */
    private async deliverOrder(orderInfo: any, ip: string, url: string, out_trade_no: string): Promise<{
        code: number;
        msg: string
    }> {
        return new Promise((resolve) => {
            const sendMsg = new Msg();
            logger.info("通知游戏服务器url", {url: url});

            sendMsg.connect(url, Account);
            setTimeout(async () => {
                try {
                    // 构建消息参数
                    const params = JSON.stringify({
                        account: orderInfo.uid,
                        channel_id: orderInfo.channel_id,
                        order: orderInfo.order_id,
                        id: orderInfo.product_id,
                        cnt: 100,
                        money: orderInfo.amount,
                    });

                    logger.info("通知游戏服务器参数", {data: params});
                    logger.info("通知游戏服务器orderInfo", {orderInfo: orderInfo});
                    let send_res = sendMsg.CG_ASK_LOGIN(
                        Account,
                        0,
                        "",
                        "cn",
                        "CN",
                        ip,
                        params,
                        orderInfo.server_id
                    );

                    if (!send_res) {
                        resolve({code: 0, msg: "通知服务器失败"});
                        return;
                    }

                    // 更新订单状态
                    const update_time = formatDate(new Date());
                    const res = await Order.updateOrderStats(
                        orderInfo.order_id,
                        2,
                        out_trade_no,
                        update_time,
                        orderInfo.uid
                    );

                    if (res.affectedRows <= 0) {
                        logger.info(`订单${orderInfo.order_id} 发货失败`);
                        resolve({code: 0, msg: "发货失败"});
                        return;
                    }

                    resolve({code: 1, msg: "发货成功"});
                } catch (error) {
                    logger.error("发货过程出错:", error);
                    resolve({code: 0, msg: "发货失败"});
                }
            }, 1500);
        });
    }

    /**
     * 通用签名生成函数
     * @param params 参数对象
     * @param privateKey 私钥
     * @param excludeKeys 需要排除的键（如sign）
     * @param needUrlEncode 是否需要URL编码
     * @returns 签名结果
     */
    public generateCommonSignature(
        params: any,
        privateKey: string,
        excludeKeys: string[] = ['sign'],
        needUrlEncode: boolean = true
    ): string {
        try {
            // 1. 过滤掉空值和排除的键
            const filteredParams: any = {};
            Object.keys(params).forEach(key => {
                if (!excludeKeys.includes(key) && params[key] !== null && params[key] !== undefined && params[key] !== '') {
                    filteredParams[key] = params[key].toString();
                }
            });

            // 2. 按字母顺序排序并构建查询字符串
            const sortedKeys = Object.keys(filteredParams).sort();
            const queryString = sortedKeys.map(key => {
                const value = filteredParams[key];
                const encodedValue = needUrlEncode ? encodeURIComponent(value) : value;
                return `${key}=${encodedValue}`;
            }).join('&');

            // 3. 拼接私钥
            const stringToSign = `${queryString}&key=${privateKey}`;
            console.log("String to Sign:", stringToSign);
            // 4. 计算MD5并转大写
            const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();

            logger.info("通用签名生成详情:", {
                filteredParams,
                queryString,
                stringToSign,
                signature
            });

            return signature;
        } catch (error) {
            logger.error("通用签名生成出错:", error);
            return '';
        }
    }

    /**
     * 小程序签名函数（签名算法3）- 兼容旧接口
     * @param parameters 参数数组
     * @param privateKey 私钥
     * @returns 签名结果
     */
    private generateSignature(parameters: string[], privateKey: string): string {
        // 按照签名算法3处理
        // 1. 过滤掉空值参数
        const filteredParams = parameters.filter(param => {
            const [key, value] = param.split('=');
            return key && value && value.trim() !== '';
        });

        // 2. 按字母顺序排序
        filteredParams.sort();

        // 3. 对参数值进行URL编码，然后用&连接
        const encodedParams = filteredParams.map(param => {
            const [key, value] = param.split('=');
            return `${key}=${encodeURIComponent(value)}`;
        });
        const queryString = encodedParams.join('&');

        // 4. 添加私钥
        const stringToSign = `${queryString}&key=${privateKey}`;

        // 5. MD5哈希并转大写
        const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();

        logger.info("签名算法3生成详情:", {
            filteredParams,
            encodedParams,
            queryString,
            stringToSign,
            signature
        });

        return signature;
    }

    /**
     * 通用签名验证函数
     * @param data 请求数据
     * @param privateKey 私钥
     * @param signKey 签名字段名
     * @param excludeKeys 需要排除的键
     * @param needUrlEncode 是否需要URL编码
     * @returns 验证结果
     */
    private verifyCommonSignature(
        data: any,
        privateKey: string,
        signKey: string = 'sign',
        excludeKeys: string[] = ['sign'],
        needUrlEncode: boolean = true
    ): boolean {
        try {
            const receivedSignature = data[signKey];
            if (!receivedSignature) {
                return false;
            }

            const expectedSignature = this.generateCommonSignature(data, privateKey, excludeKeys, needUrlEncode);

            logger.info("通用签名验证详情:", {
                receivedSignature,
                expectedSignature,
                isValid: receivedSignature === expectedSignature
            });

            return receivedSignature === expectedSignature;
        } catch (error) {
            logger.error("通用签名验证出错:", error);
            return false;
        }
    }

    /**
     * 验证iOS支付签名（签名算法3）
     * @param params 请求参数
     * @param config 渠道配置
     * @returns 验证结果
     */
    private verifyPaymentSignature(params: any, config: ChannelConfig): boolean {
        try {
            // 获取签名密钥
            const signKey = config.paymentConfig.signKey;
            if (!signKey) {
                logger.error("iOS支付签名密钥未配置");
                return false;
            }

            // 过滤掉sign参数，按参数名排序
            const sortedParams = Object.keys(params)
                .filter(key => key !== 'sign')
                .sort()
                .map(key => `${key}=${params[key]}`);

            // 构建签名字符串
            const signString = sortedParams.join('&') + `&key=${signKey}`;

            // 计算MD5签名
            const expectedSignature = CryptoJS.MD5(signString).toString().toUpperCase();

            logger.info("iOS支付签名验证", {
                signString,
                receivedSignature: params.sign,
                expectedSignature,
                isValid: params.sign === expectedSignature
            });

            return params.sign === expectedSignature;
        } catch (error) {
            logger.error("iOS支付签名验证出错:", error);
            return false;
        }
    }

    /**
     * 内部订单校验方法
     * @param notifyId 平台通知ID
     * @param gameId 游戏ID
     * @param config 渠道配置
     * @returns 校验结果
     */
    private async verifyOrderInternal(notifyId: string, gameId: string, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
        try {
            // 构建验证参数
            const parameters = [
                `gameid=${gameId}`,
                `notify_id=${notifyId}`
            ];

            // 生成签名
            const signature = this.generatePaymentSignature(parameters, config.paymentConfig.signKey!);
            const apiUrl = `https://login.11h5.com/pay/paygate/verify.php?${parameters.join('&')}&sign=${signature}`;

            logger.info("iOS订单校验请求", { apiUrl });

            // 调用第三方API验证订单
            const response = await axios.get(apiUrl, {
                timeout: 10000,
                headers: {
                    'User-Agent': 'Mozilla/5.0 (compatible; GameServer/1.0)'
                }
            });

            logger.info("iOS订单校验响应", {
                status: response.status,
                data: response.data
            });

            if (response.status === 200) {
                const result = response.data;
                // 处理纯文本"SUCCESS"响应
                if (result === "SUCCESS") {
                    return { success: true, message: "订单校验成功" };
                }
                // 处理JSON格式响应
                else if (result && typeof result === 'object' && result.code === 0) {
                    return { success: true, message: "订单校验成功" };
                } else {
                    return {
                        success: false,
                        message: result?.msg || "订单校验失败"
                    };
                }
            } else {
                return {
                    success: false,
                    message: `HTTP错误: ${response.status}`
                };
            }
        } catch (error) {
            logger.error("iOS订单校验出错:", error);
            return {
                success: false,
                message: error.message || "订单校验异常"
            };
        }
    }

    /**
     * 游戏圈发货接口
     * 微信SDK回调，发货礼包给玩家
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async deliverGoods(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const body = ctx.request.body as any;
            const { timestamp, nonce, signature, wxMsg,uid } = body;

            // 验证签名（签名算法1：SHA1）
            const verifyConfig = this.getChannel11Config('miniapp');
            const expectedSignature = this.generateContentSecuritySignature({ timestamp, nonce }, verifyConfig);
            if (!expectedSignature || expectedSignature !== signature) {
                logger.error("游戏圈发货签名验证失败", { received: signature, expected: expectedSignature });
                return { code: -1, msg: "签名验证失败" };
            }

            const miniGame = wxMsg?.MiniGame;
            if (!miniGame) {
                logger.error("游戏圈发货：缺少MiniGame参数");
                return { code: 0, msg: "ok" };
            }

            const { OrderId, ToUserOpenid, GiftTypeId, GiftId, GoodsList, Zone, IsPreview } = miniGame;
            if (!OrderId || !uid || !GoodsList) {
                logger.error("游戏圈发货：缺少必要参数", { OrderId, uid });
                return { code: 0, msg: "ok" };
            }

            logger.info("游戏圈发货请求", { OrderId, ToUserOpenid, GiftTypeId, GiftId, Zone, IsPreview,uid });

            // 查询玩家最近登录的服务器
            const Server = require("../../model/ServerModel");
            const serverList = await Server.getEnterServerListByUid(uid, 11);
            if (!serverList || serverList.length === 0) {
                logger.warn("游戏圈发货：未找到玩家服务器记录", { uid });
                return { code: 0, msg: "ok" };
            }

            // 取最近登录的服务器
            const serverInfo = serverList[0];

            // 将 GoodsList 转换为邮件道具格式 [[itemId, count], ...]
            const items: Array<[number, number]> = (GoodsList as any[]).map(good => [
                Number(good.Id),
                Number(good.Num),
            ]);

            // newUniqueTag 格式与 Lua 保持一致："channelId|serverId|account"
            const newUniqueTag = `11|${serverInfo.server_id}|${uid}`;

            logger.info("游戏圈发货 - 直接写邮件到DB", {
                OrderId, uid, dbName: serverInfo.db_name, newUniqueTag, itemCnt: items.length,
            });

            const ok = await insertMailToPlayer(
                serverInfo.db_name,
                newUniqueTag,
                "游戏圈礼物",
                "您有一份游戏圈礼物待领取",
                items,
            );

            if (!ok) {
                logger.warn("游戏圈发货：邮件写入失败", { OrderId, uid });
            } else {
                logger.info("游戏圈发货成功", { OrderId,uid });
            }

            return { code: 0, msg: "ok" };

        } catch (error) {
            logger.error("游戏圈发货出错:", error);
            return { code: 0, msg: "ok" };
        }
    }

    /**
     * 生成iOS支付签名（签名算法3）
     * @param parameters 参数数组
     * @param signKey 签名密钥
     * @returns 签名字符串
     */
    private generatePaymentSignature(parameters: string[], signKey: string): string {
        try {
            // 构建签名字符串
            const signString = parameters.join('&') + `&key=${signKey}`;

            // 计算MD5签名并转为大写
            const signature = CryptoJS.MD5(signString).toString().toUpperCase();

            logger.info("生成iOS支付签名", {
                signString,
                signature
            });

            return signature;
        } catch (error) {
            logger.error("生成iOS支付签名出错:", error);
            return "";
        }
    }
}