import {Context} from "koa";
import axios from "axios";
import * as crypto from 'crypto';
import {ChannelHandler, LoginResult, PaymentResult} from "../interfaces/ChannelHandler";
import {ChannelConfig} from "../../config/channelConfig";
import {PaymentHelper} from "../../utils/PaymentHelper";
import {ChannelConfigManager} from "../../utils/ChannelConfigManager";
import {MeituanChannelHandler} from "./MeituanChannelHandler";

const logger = require("../../utils/log");

const meituanHandler = new MeituanChannelHandler();

/**
 * 华为渠道处理器
 * 负责登录验证与支付回调处理
 */
export class HuaweiChannelHandler implements ChannelHandler {
    /**
     * 获取HTTPS代理配置
     * @returns HTTPS代理配置
     */
    private getHttpsAgent() {
        const https = require('https');
        return new https.Agent({
            rejectUnauthorized: false,
            secureProtocol: 'TLSv1_2_method',
            timeout: 10000
        });
    }

    /**
     * 生成签名
     * 根据文档：移除空值参数 -> 按字母顺序排序 -> 拼接参数 -> 拼接secret -> MD5
     * @param params 请求参数对象
     * @param secret 应用密钥
     * @returns MD5签名字符串（32位小写）
     */
    private generateSign(params: any, secret: string): string {
        try {
            // 1. 移除空值参数
            const filteredParams: any = {};
            Object.keys(params).forEach(key => {
                if (params[key] !== null && params[key] !== undefined && params[key] !== '') {
                    filteredParams[key] = params[key].toString();
                }
            });

            // 2. 按字母顺序排序
            const sortedKeys = Object.keys(filteredParams).sort();

            // 3. 构建签名字符串：key=value&key=value
            const queryString = sortedKeys.map(key => {
                return `${key}=${filteredParams[key]}`;
            }).join('&');

            // 4. 拼接secret key
            const signStr = `${queryString}&key=${secret}`;

            logger.info("华为渠道签名生成详情:", {
                filteredParams,
                queryString,
                signStr
            });

            // 5. MD5哈希（32位小写）
            const signature = crypto.createHash('md5').update(signStr).digest('hex').toLowerCase();

            return signature;
        } catch (error) {
            logger.error("华为渠道签名生成出错:", error);
            return '';
        }
    }

    /**
     * 华为渠道登录鉴权
     * platform=mtminiapp 时走美团逻辑，否则走华为逻辑
     * @param ctx Koa上下文
     * @param config 渠道配置
     * @returns 登录结果
     */
    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            const platform = data?.platform;

            // platform=mtminiapp 时调用美团登录逻辑
            if (platform === 'mtminiapp') {
                const meituanConfig = ChannelConfigManager.getConfig(16);
                if (!meituanConfig) {
                    logger.error("美团渠道配置不存在");
                    return { code: -1, msg: "渠道配置错误", data: null };
                }
                logger.info("channelId=17, platform=mtminiapp, 委托美团渠道处理登录");
                return await meituanHandler.handleLogin(ctx, meituanConfig);
            }

            // platform=tbminiapp 时使用淘宝渠道配置
            if (platform === 'tbminiapp') {
                const taobaoConfig = ChannelConfigManager.getConfig(19);
                if (!taobaoConfig) {
                    logger.error("淘宝渠道配置不存在");
                    return { code: -1, msg: "渠道配置错误", data: null };
                }
                logger.info("channelId=17, platform=tbminiapp, 使用淘宝渠道配置处理登录");
                config = taobaoConfig;
            }

            const { token } = data;

            // 验证必要参数
            if (!token) {
                logger.error("华为渠道登录鉴权失败 - 缺少token参数");
                return {
                    code: -1,
                    msg: "缺少必要参数: token",
                    data: null
                };
            }

            // 获取配置
            const appId = config.loginConfig?.appId;
            const appSecret = config.loginConfig?.appSecret;

            if (!appId || !appSecret) {
                logger.error("华为渠道登录鉴权失败 - 缺少配置参数", { appId, appSecret: !!appSecret });
                return {
                    code: -1,
                    msg: "服务器配置错误: 缺少appId或appSecret",
                    data: null
                };
            }

            // 构建请求参数
            const timestamp = Math.floor(Date.now() / 1000).toString();
            const requestBody = {
                appId: appId,
                timestamp: timestamp
            };

            // 生成签名
            const sign = this.generateSign(requestBody, appSecret);

            if (!sign) {
                logger.error("华为渠道登录鉴权失败 - 签名生成失败");
                return {
                    code: -1,
                    msg: "签名生成失败",
                    data: null
                };
            }

            // 构建请求头
            const headers = {
                'Accept': 'application/json;',
                'Content-Type': 'application/json;charset=utf-8;',
                'Authorization': token,
                'sign': sign,
                'Server-Plat-From': 'minigame_server' // 可选，但建议传递
            };

            // API地址
            const apiUrl = 'https://sdkapi.haotianhuyu.com/api/user/getLoginStatus';

            logger.info("华为渠道登录鉴权请求", {
                url: apiUrl,
                headers: { ...headers, Authorization: token ? '***' : undefined },
                body: requestBody
            });

            // 发送请求
            const response = await axios.post(apiUrl, requestBody, {
                headers: headers,
                timeout: 10000,
                httpsAgent: this.getHttpsAgent(),
                validateStatus: (status) => {
                    // 根据文档，失败时HTTP状态码是401，但我们也接受200
                    return status === 200 || status === 401;
                }
            });

            logger.info("华为渠道登录鉴权响应", {
                status: response.status,
                data: response.data
            });

            const responseData = response.data;

            // 判断登录结果
            // 根据文档：status=20000 表示成功，其他都是失败
            if (responseData.status === 20000) {
                // 登录成功
                logger.info("华为渠道登录鉴权成功", {
                    user_id: responseData.data?.user_id,
                    token: responseData.data?.token ? '***' : undefined
                });

                return {
                    code: 0,
                    msg: responseData.message || "登录成功",
                    data: {
                        token: responseData.data?.token,
                        user_id: responseData.data?.user_id,
                        ali_user_id: responseData.data?.ali_user_id,
                        channel_open_id: responseData.data?.channel_open_id
                    }
                };
            } else {
                // 登录失败
                logger.warn("华为渠道登录鉴权失败", {
                    status: responseData.status,
                    errCode: responseData.errCode,
                    message: responseData.message,
                    msg: responseData.msg
                });

                return {
                    code: -1,
                    msg: responseData.msg || responseData.message || "登录验证失败",
                    data: null
                };
            }

        } catch (error: any) {
            logger.error("华为渠道登录鉴权出错:", error);
            
            // 处理axios错误
            if (error.response) {
                const responseData = error.response.data;
                logger.error("华为渠道登录鉴权API错误响应", {
                    status: error.response.status,
                    data: responseData
                });

                // 如果返回了错误数据，尝试解析
                if (responseData && responseData.status !== undefined) {
                    return {
                        code: -1,
                        msg: responseData.msg || responseData.message || "登录验证失败",
                        data: null
                    };
                }
            }

            return {
                code: -1,
                msg: error.message || "登录验证失败",
                data: null
            };
        }
    }

    /**
     * 验证支付回调签名
     * 根据文档：移除sign参数和空值 -> 按ASCII码升序排序 -> 拼接成key=value格式 -> 拼接&key={callback secret} -> MD5
     * @param data 回调参数对象
     * @param callbackSecret 回调密钥
     * @returns 验证结果
     */
    private verifyPaymentSign(data: any, callbackSecret: string): boolean {
        try {
            // 1. 移除sign参数和空值字段
            const filteredParams: any = {};
            Object.keys(data).forEach(key => {
                if (key !== 'sign' && data[key] !== null && data[key] !== undefined && data[key] !== '') {
                    filteredParams[key] = data[key].toString();
                }
            });

            // 2. 按ASCII码升序排序
            const sortedKeys = Object.keys(filteredParams).sort();

            // 3. 构建签名字符串：key1=value1&key2=value2
            const queryString = sortedKeys.map(key => {
                return `${key}=${filteredParams[key]}`;
            }).join('&');

            // 4. 拼接回调密钥
            const signStr = `${queryString}&key=${callbackSecret}`;

            logger.info("华为渠道支付回调签名验证详情:", {
                filteredParams,
                queryString,
                signStr: signStr.substring(0, 100) + '...' // 只显示前100个字符
            });

            // 5. MD5哈希（32位小写）
            const calculatedSign = crypto.createHash('md5').update(signStr).digest('hex').toLowerCase();
            const receivedSign = (data.sign || '').toLowerCase();

            const isValid = calculatedSign === receivedSign;

            logger.info("华为渠道支付回调签名验证结果:", {
                calculatedSign,
                receivedSign,
                isValid
            });

            return isValid;
        } catch (error) {
            logger.error("华为渠道支付回调签名验证出错:", error);
            return false;
        }
    }

    /**
     * 华为渠道支付回调处理
     * platform=mtminiapp 时走美团逻辑，否则走华为逻辑
     * @param ctx Koa上下文
     * @param config 渠道配置
     * @returns 支付结果（注意：返回格式为 {errCode: 0} 或 {errCode: 1, errMsg: "..."}）
     */
    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
        const startTime = Date.now();
        
        try {
            const data = ctx.request.body as any;
            const query = ctx.query as any;
            const platform = data?.platform || query?.platform;

            logger.info("华为渠道支付回调参数:", { url: ctx.href, params: data, platform });

            // platform=mtminiapp 时调用美团支付回调逻辑
            if (platform === 'mtminiapp') {
                const meituanConfig = ChannelConfigManager.getConfig(16);
                if (!meituanConfig) {
                    logger.error("美团渠道配置不存在");
                    return { code: 1, msg: "渠道配置错误" };
                }
                logger.info("channelId=17, platform=mtminiapp, 委托美团渠道处理支付回调");
                return await meituanHandler.handlePayment(ctx, meituanConfig);
            }

            // platform=tbminiapp 时使用淘宝渠道配置
            if (platform === 'tbminiapp') {
                const taobaoConfig = ChannelConfigManager.getConfig(19);
                if (!taobaoConfig) {
                    logger.error("淘宝渠道配置不存在");
                    return { code: 1, msg: "渠道配置错误" };
                }
                logger.info("channelId=17, platform=tbminiapp, 使用淘宝渠道配置处理支付回调");
                config = taobaoConfig;
            }

            // 1. 验证必要参数
            const requiredParams = ['app_id', 'user_id', 'server_id', 'role_id', 'cp_order_id', 
                                   'cs_order_no', 'cs_trade_no', 'pay_amount', 'swap_coin_num', 
                                   'order_create_time', 'order_pay_time', 'order_status', 'sign'];
            
            const missingParams = requiredParams.filter(param => !data[param]);
            if (missingParams.length > 0) {
                logger.warn("华为渠道支付回调失败: 缺少必要参数", { missingParams });
                return {
                    code: 1,
                    msg: `缺少必要参数: ${missingParams.join(', ')}`
                };
            }

            // 2. 验证订单状态（只有SUCCESS状态才发货）
            if (data.order_status !== 'SUCCESS') {
                logger.warn("华为渠道支付回调失败: 订单状态非成功", { order_status: data.order_status });
                return {
                    code: 1,
                    msg: `订单状态非成功: ${data.order_status}`
                };
            }

            // 3. 获取回调密钥并验证签名
            const callbackSecret = config.paymentConfig?.callbackKey;
            if (!callbackSecret) {
                logger.error("华为渠道支付回调失败: 未配置回调密钥");
                return {
                    code: 1,
                    msg: "服务器配置错误: 未配置回调密钥"
                };
            }

            // 验证签名（必须验证，只有签名正确的订单才可发货）
            if (!this.verifyPaymentSign(data, callbackSecret)) {
                logger.error("华为渠道支付回调失败: 签名验证失败");
                return {
                    code: 1,
                    msg: "签名验证失败"
                };
            }

            // 4. 验证订单（使用cp_order_id作为订单ID）
            const orderId = data.cp_order_id;
            const validation = await PaymentHelper.validateOrder(orderId);
            
            if (!validation.valid) {
                // 如果是重复发货，需要返回成功响应，但不重复发货
                if (validation.message?.includes("重复发货")) {
                    logger.info("华为渠道支付回调: 订单已发货，返回成功响应", { orderId });
                    return {
                        code: 0,
                        msg: "订单已发货"
                    };
                }
                
                logger.warn("华为渠道支付回调订单验证失败", {
                    orderId,
                    validation
                });
                return {
                    code: 1,
                    msg: validation.message || "订单验证失败"
                };
            }

            const orderInfo = validation.orderInfo;

            // 5. 验证金额（pay_amount单位是分，需要转换为元进行比较）
            const paymentAmount = parseInt(data.pay_amount) / 100; // 转换为元
            if (Math.abs(Number(orderInfo.amount) - paymentAmount) > 0.01) {
                logger.warn("华为渠道支付回调金额不匹配", {
                    orderId,
                    orderAmount: orderInfo.amount,
                    paymentAmount: paymentAmount
                });
                return {
                    code: 1,
                    msg: `订单金额不一致: 订单金额${orderInfo.amount}元，支付金额${paymentAmount}元`
                };
            }

            // 6. 发货处理
            logger.info(`华为渠道支付订单${orderId}开始发货`, {
                cs_order_no: data.cs_order_no,
                cs_trade_no: data.cs_trade_no,
                amount: paymentAmount,
                swap_coin_num: data.swap_coin_num
            });

            const result = await PaymentHelper.deliverOrder(
                orderInfo,
                ctx.request.ip,
                validation.url,
                data.cs_order_no // 使用传盛订单号作为out_trade_no
            );

            // 检查是否超时（必须在7秒内响应）
            const elapsedTime = Date.now() - startTime;
            if (elapsedTime > 7000) {
                logger.warn("华为渠道支付回调响应超时", {
                    orderId,
                    elapsedTime: `${elapsedTime}ms`
                });
            }

            // 7. 返回响应（注意格式：成功返回 {errCode: 0}，失败返回 {errCode: 1, errMsg: "..."}）
            // PaymentHelper.deliverOrder 成功返回 code=1，失败返回 code=0
            // 华为渠道要求：成功返回 errCode=0，失败返回 errCode=1
            if (result.code === 1) {
                // 发货成功
                logger.info(`华为渠道支付订单${orderId}发货成功`, {
                    elapsedTime: `${elapsedTime}ms`
                });
                // 返回 code=0 表示成功，ApiController会转换为 {errCode: 0}
                return {
                    code: 0,
                    msg: "发货成功"
                };
            } else {
                // 发货失败
                logger.error(`华为渠道支付订单${orderId}发货失败`, {
                    result,
                    elapsedTime: `${elapsedTime}ms`
                });
                // 返回 code=1 表示失败，ApiController会转换为 {errCode: 1, errMsg: "..."}
                return {
                    code: 1,
                    msg: `发放失败,原因:${result.msg || "未知错误"}`
                };
            }

        } catch (error: any) {
            const elapsedTime = Date.now() - startTime;
            logger.error("华为渠道支付回调异常", { 
                error: error.message, 
                stack: error.stack,
                elapsedTime: `${elapsedTime}ms`
            });
            
            return {
                code: 1,
                msg: `发放失败,原因:${error.message || "未知错误"}`
            };
        }
    }
}

