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";

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

/**
 * 美团渠道处理器
 * 负责登录验证与支付回调处理
 */
export class MeituanChannelHandler implements ChannelHandler {
    /**
     * 美团登录验证
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            const { code } = data;

            // 验证必要参数
            if (!code) {
                logger.warn("美团登录验证失败: 缺少必要参数 code", { data });
                return {
                    code: 0,
                    msg: "缺少必要参数: code"
                };
            }

            // 获取配置中的应用ID和应用密钥
            const appId = config.loginConfig?.appId;
            const appSecret = config.loginConfig?.appSecret;

            if (!appId || !appSecret) {
                logger.error("美团登录验证失败: 未配置appId或appSecret");
                return {
                    code: 0,
                    msg: "服务器配置错误: 未配置appId或appSecret"
                };
            }

            // 构建请求URL
            const apiUrl = "https://mgc.meituan.com/mgc/gateway/api/v3/mg/jscode2session";

            // 构建请求体
            const requestBody = {
                appId: appId,
                appSecret: appSecret,
                code: code,
                grantType: "authorization_code"
            };

            logger.info("美团登录验证请求", { url: apiUrl, requestBody: { ...requestBody, appSecret: "***" } });

            // 发送POST请求
            const response = await axios.post(apiUrl, requestBody, {
                headers: {
                    "Content-Type": "application/json"
                },
                timeout: 10000
            });

            logger.info("美团登录验证响应", { status: response.status, data: response.data });

            // 解析响应
            const responseData = response.data;

            // 根据返回的code判断成功与否（通常0表示成功）
            if (responseData.code === 0 && responseData.msg === "ok") {
                // 提取用户信息
                const data = responseData.data;
                const mgcIds = data?.mgcIds || data?.mgclds || [];
                const mgcIdsStr = data?.mgcIdsStr || data?.mgcldsStr || [];
                const accessToken = data?.accessToken;

                // 取第一个角色ID（根据文档说明：取 mgclds 第一个元素即可）
                const userId = mgcIds.length > 0 ? mgcIds[0] : (mgcIdsStr.length > 0 ? mgcIdsStr[0] : null);

                if (!userId) {
                    logger.warn("美团登录验证失败: 未获取到用户ID", { data });
                    return {
                        code: 0,
                        msg: "登录验证失败: 未获取到用户ID"
                    };
                }

                logger.info("美团登录验证成功", { userId, accessToken });

                return {
                    code: 1,
                    msg: "success",
                    data: {
                        userId: userId.toString(),
                        accessToken: accessToken,
                        channelId: config.channelId,
                        platform: config.platform
                    }
                };
            } else {
                logger.warn("美团登录验证失败: 接口返回错误", { responseData });
                return {
                    code: 0,
                    msg: responseData.msg || "登录验证失败"
                };
            }
        } catch (error: any) {
            logger.error("美团登录验证异常", { error: error.message, stack: error.stack });
            
            // 处理axios错误
            if (error.response) {
                logger.error("美团登录验证API错误响应", {
                    status: error.response.status,
                    data: error.response.data
                });
                return {
                    code: 0,
                    msg: `登录验证失败: ${error.response.data?.msg || "API请求失败"}`
                };
            }

            return {
                code: 0,
                msg: "登录验证异常: " + (error.message || "未知错误")
            };
        }
    }

    /**
     * 美团支付回调
     * @param ctx Koa上下文
     * @param config 渠道配置
     */
    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
        try {
            const data = ctx.request.body as any;
            const { sign, data: encryptedData } = data;

            logger.info("美团支付回调参数", { url: ctx.href, hasSign: !!sign, hasData: !!encryptedData });

            // 验证必要参数
            if (!sign || !encryptedData) {
                logger.warn("美团支付回调失败: 缺少必要参数", { sign: !!sign, data: !!encryptedData });
                return {
                    code: 0,
                    msg: "缺少必要参数: sign 或 data"
                };
            }

            // 获取配置中的应用ID和应用密钥
            const appId = config.loginConfig?.appId;
            const appSecret = config.loginConfig?.appSecret;

            if (!appId || !appSecret) {
                logger.error("美团支付回调失败: 未配置appId或appSecret");
                return {
                    code: 0,
                    msg: "服务器配置错误: 未配置appId或appSecret"
                };
            }

            // 1. 验证签名
            const isValidSign = this.verifySignature(encryptedData, sign, appId, appSecret);
            if (!isValidSign) {
                logger.warn("美团支付回调失败: 签名验证失败", { sign });
                return {
                    code: 0,
                    msg: "签名验证失败"
                };
            }

            // 2. 解密数据
            const decryptedData = this.decryptData(encryptedData, appId, appSecret);
            if (!decryptedData) {
                logger.error("美团支付回调失败: 数据解密失败");
                return {
                    code: 0,
                    msg: "数据解密失败"
                };
            }

            logger.info("美团支付回调解密数据", { decryptedData });

            // 3. 解析订单信息
            const { bizOrderId, mgcOrderId, mgcId, price, payStatus } = decryptedData;

            // 验证必要字段
            if (!bizOrderId || !mgcOrderId || !mgcId || !price || !payStatus) {
                logger.warn("美团支付回调失败: 解密数据缺少必要字段", { decryptedData });
                return {
                    code: 0,
                    msg: "解密数据缺少必要字段"
                };
            }

            // 4. 验证支付状态
            if (payStatus !== "OK") {
                logger.warn("美团支付回调失败: 支付状态非成功", { payStatus });
                return {
                    code: 0,
                    msg: `支付状态失败: ${payStatus}`
                };
            }

            // 5. 验证订单
            const validation = await PaymentHelper.validateOrder(bizOrderId);
            if (!validation.valid) {
                logger.warn("美团支付回调订单验证失败", {
                    bizOrderId,
                    validation
                });
                return {
                    code: validation.message?.includes("重复发货") ? 1 : 0,
                    msg: validation.message || "订单验证失败"
                };
            }

            const orderInfo = validation.orderInfo;

            // 6. 验证金额（美团返回的是分，需要转换为元进行比较）
            const paymentAmount = parseFloat(price) / 100; // 转换为元
            if (Math.abs(Number(orderInfo.amount) - paymentAmount) > 0.01) {
                logger.warn("美团支付回调金额不匹配", {
                    bizOrderId,
                    orderAmount: orderInfo.amount,
                    paymentAmount: paymentAmount
                });
                return {
                    code: 0,
                    msg: "订单金额不一致"
                };
            }

            // 7. 发货处理
            logger.info(`美团支付订单${bizOrderId}开始发货`, {
                mgcOrderId,
                mgcId,
                amount: paymentAmount
            });

            const result = await PaymentHelper.deliverOrder(
                orderInfo,
                ctx.request.ip,
                validation.url,
                mgcOrderId
            );

            logger.info(`美团支付订单${bizOrderId}发货完成`, { result });
            return result;

        } catch (error: any) {
            logger.error("美团支付回调异常", { error: error.message, stack: error.stack });
            return {
                code: 0,
                msg: "支付回调异常: " + (error.message || "未知错误")
            };
        }
    }

    /**
     * 生成密钥
     * 根据文档JS demo：SHA1(appId + "&" + appSecret) 取原始字节补零到32字节，再base64编码
     */
    private createSecretKey(appId: string, appSecret: string): string {
        const password = appId + "&" + appSecret;
        const sha1Bytes = crypto.createHash('sha1').update(password).digest();
        const key = Buffer.concat([sha1Bytes, Buffer.alloc(32, 0)]).slice(0, 32);
        return key.toString('base64');
    }

    /**
     * 验证签名
     * 根据文档：signature = SHA1(data + secretKey)
     * secretKey = base64(SHA1_raw(appId + "&" + appSecret) 补零到32字节)
     */
    private verifySignature(data: string, sign: string, appId: string, appSecret: string): boolean {
        try {
            const secretKey = this.createSecretKey(appId, appSecret);
            const calculatedSign = crypto.createHash('sha1').update(data + secretKey).digest('hex');

            logger.info("美团签名验证", { secretKey, calculatedSign, receivedSign: sign });

            return calculatedSign.toLowerCase() === sign.toLowerCase();
        } catch (error) {
            logger.error("美团签名验证异常", { error });
            return false;
        }
    }

    /**
     * 解密数据
     * 根据文档：AES-256-GCM解密
     * 数据格式：urlsafe_base64(IV[16] + 密文 + AuthTag[16])
     */
    private decryptData(encryptedData: string, appId: string, appSecret: string): any {
        try {
            const secretKey = this.createSecretKey(appId, appSecret);
            const keyBuffer = Buffer.from(secretKey, 'base64');

            // URL-safe base64 转标准 base64
            const normalized = encryptedData.replace(/-/g, '+').replace(/_/g, '/');
            const decoded = Buffer.from(normalized, 'base64');

            const iv = decoded.slice(0, 16);
            const authTag = decoded.slice(-16);
            const content = decoded.slice(16, -16);

            const decipher = crypto.createDecipheriv('aes-256-gcm', keyBuffer, iv);
            decipher.setAuthTag(authTag);
            const decrypted = decipher.update(content, undefined, 'utf8');

            const parsed = JSON.parse(decrypted);
            logger.info("美团数据解密成功（AES-256-GCM）");
            return parsed;
        } catch (error: any) {
            logger.error("美团数据解密异常", { error: error.message, stack: error.stack });
            return null;
        }
    }
}

