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

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

// 开服同步接口定义
export interface ServerSyncParams {
    GAME_ID: number;
    SID: number;
    _SID: number | string;
    NAME: string;
    START_TIME: string;
    timestamp: number;
    sign: string;
}

export interface ServerSyncResult {
    status: number;
    msg: string;
}

export class MianyouChannelHandler implements ChannelHandler {
    /**
     * 处理登录验证
     * @param ctx Koa上下文
     * @param config 渠道配置
     * @returns 登录结果
     */
    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
        try {
            const data = ctx.request.body as any;
            const {uid, timestamp, token} = data;
            let username = uid;
            // 验证必要参数
            if (!username || !timestamp || !token) {
                logger.warn('Mianyou登录验证失败: 缺少必要参数', {username, timestamp, token});
                return {
                    code: 400,
                    msg: '缺少必要参数: username, timestamp, token'
                };
            }

            // 获取登录验证密钥
            const loginKey = config.loginConfig?.signKey;
            if (!loginKey) {
                logger.error('Mianyou登录验证失败: 未配置登录密钥');
                return {
                    code: 500,
                    msg: '服务器配置错误: 未配置登录密钥'
                };
            }

            // 验证token
            const expectedToken = this.generateToken(username, timestamp, loginKey);
            if (token.toLowerCase() !== expectedToken.toLowerCase()) {
                console.log("timestamp:", timestamp,username,loginKey);
                logger.warn('Mianyou登录验证失败: token验证失败', {
                    loginKey,
                    username,
                    timestamp,
                    receivedToken: token,
                    expectedToken
                });
                return {
                    code: 401,
                    msg: '登录验证失败: token无效'
                };
            }

            // 验证时间戳（可选：检查时间戳是否在有效期内，比如5分钟内）
            const currentTime = Math.floor(Date.now() / 1000);
            const timeDiff = Math.abs(currentTime - timestamp);
            const maxTimeDiff = 300; // 5分钟

            if (timeDiff > maxTimeDiff) {
                logger.warn('Mianyou登录验证失败: 时间戳过期', {
                    username,
                    timestamp,
                    currentTime,
                    timeDiff
                });
                return {
                    code: 401,
                    msg: '登录验证失败: 时间戳过期'
                };
            }

            logger.info('Mianyou登录验证成功', {username, timestamp});

            return {
                code: 0,
                msg: '登录验证成功',
                data: {
                    username,
                    timestamp,
                    channelId: config.channelId,
                    platform: config.platform
                }
            };

        } catch (error) {
            logger.error('Mianyou登录验证异常', error);
            return {
                code: 500,
                msg: '服务器内部错误'
            };
        }
    }

    /**
     * 处理支付验证
     * @param ctx Koa上下文
     * @param config 渠道配置
     * @returns 支付结果
     */
    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
        try {
            // 获取GET请求参数
            const params = ctx.query as any;
            const {
                username,
                order_id,
                server,
                amount,
                extra,
                sandbox,
                timestamp,
                sign
            } = params;
            let cpOrderId = extra
            // 验证必要参数
            if (!username || !order_id || !server || !amount || !extra|| !sandbox || !timestamp || !sign) {
                logger.warn('Mianyou支付验证失败: 缺少必要参数', {
                    username, order_id, server, amount, extra, sandbox, timestamp, sign
                });
                return {
                    code: 400,
                    msg: '缺少必要参数'
                };
            }

            // 获取支付回调密钥
            const paymentKey = config.paymentConfig?.signKey;
            if (!paymentKey) {
                logger.error('Mianyou支付验证失败: 未配置支付回调密钥');
                return {
                    code: 500,
                    msg: '服务器配置错误: 未配置支付回调密钥'
                };
            }

            // 验证签名
            const expectedSign = this.generatePaymentSign(
                username,
                order_id,
                server,
                amount,
                extra,
                sandbox,
                timestamp,
                paymentKey
            );

            if (sign.toLowerCase() !== expectedSign.toLowerCase()) {
                logger.warn('Mianyou支付验证失败: 签名验证失败', {
                    username,
                    order_id,
                    receivedSign: sign,
                    expectedSign
                });
                return {
                    code: 401,
                    msg: '支付验证失败: 签名无效'
                };
            }

            // 验证时间戳（5分钟内有效）
            const currentTime = Math.floor(Date.now() / 1000);
            const timeDiff = Math.abs(currentTime - parseInt(timestamp));
            const maxTimeDiff = 300; // 5分钟

            // if (timeDiff > maxTimeDiff) {
            //     logger.warn('Mianyou支付验证失败: 时间戳过期', {
            //         username,
            //         order_id,
            //         timestamp,
            //         currentTime,
            //         timeDiff
            //     });
            //     return {
            //         code: 401,
            //         msg: '支付验证失败: 时间戳过期'
            //     };
            // }

            // 验证金额格式
            const paymentAmount = parseFloat(amount);
            if (isNaN(paymentAmount) || paymentAmount <= 0) {
                logger.warn('Mianyou支付验证失败: 金额格式错误', {
                    username,
                    cpOrderId,
                    amount
                });
                return {
                    code: 400,
                    msg: '支付验证失败: 金额格式错误'
                };
            }

            // 验证沙盒参数
            const sandboxValue = parseInt(sandbox);
            if (sandboxValue !== 0 && sandboxValue !== 1) {
                logger.warn('Mianyou支付验证失败: 沙盒参数错误', {
                    username,
                    order_id,
                    sandbox
                });
                return {
                    code: 400,
                    msg: '支付验证失败: 沙盒参数错误'
                };
            }

            logger.info('Mianyou支付验证成功，开始处理发货', {
                username,
                cpOrderId,
                order_id,
                server,
                amount: paymentAmount,
                extra,
                sandbox: sandboxValue === 1
            });

            // 验证订单
            const validation = await PaymentHelper.validateOrder(cpOrderId);
            if (!validation.valid) {
                return {
                    code: validation.message?.includes("重复发货") ? 1 : 0,
                    msg: validation.message || "订单验证失败"
                };
            }
            const orderInfo = validation.orderInfo;

            // 直接调用系统封装的发货函数
            const result = await PaymentHelper.deliverOrder(
                orderInfo,
                "127.0.0.1", // 使用默认IP地址
                validation.url,
                order_id // 使用订单号作为外部交易号
            );

            // 处理支付成功逻辑
            logger.info(`Mianyou支付成功 - 用户: ${username}, 金额: ${paymentAmount}, 订单: ${cpOrderId}, 发货结果:`, result);
            return result;

        } catch (error) {
            logger.error('Mianyou支付验证异常', error);
            return {
                code: 500,
                msg: '服务器内部错误'
            };
        }
    }

    /**
     * 生成token
     * 根据文档：token = md5(username + timestamp + KEY)
     * @param username 用户名
     * @param timestamp 时间戳
     * @param key 密钥
     * @returns MD5哈希值（小写）
     */
    private generateToken(username: string, timestamp: number, key: string): string {
        const data = username + timestamp + key;
        console.log('generateToken data:', data);
        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
    }

    /**
     * 生成支付签名
     * 根据文档：sign = md5(username + order_id + server + amount + extra + sandbox + timestamp + KEY)
     * @param username 用户名
     * @param order_id 订单号
     * @param server 区服ID
     * @param amount 支付金额
     * @param extra 透传参数
     * @param sandbox 沙盒标识
     * @param timestamp 时间戳
     * @param key 密钥
     * @returns MD5哈希值（小写）
     */
    private generatePaymentSign(
        username: string,
        order_id: string,
        server: string,
        amount: string,
        extra: string,
        sandbox: string,
        timestamp: string,
        key: string
    ): string {
        const data = username + order_id + server + amount + extra + sandbox + timestamp + key;
        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
    }

    /**
     * 开服同步
     * @param params 开服同步参数
     * @param config 渠道配置
     * @returns 同步结果
     */
    async syncServerOpen(params: Omit<ServerSyncParams, 'sign'>, config: ChannelConfig): Promise<ServerSyncResult> {
        try {
            // 获取游戏ID和密钥
            const gameId = config.paymentConfig?.gameId;
            const signKey = config.paymentConfig?.signKey;

            if (!gameId || !signKey) {
                logger.error('Mianyou开服同步失败: 缺少游戏ID或签名密钥');
                return {
                    status: -2,
                    msg: '配置错误: 缺少游戏ID或签名密钥'
                };
            }

            // 构建参数对象
            const syncParams: Omit<ServerSyncParams, 'sign'> = {
                GAME_ID: parseInt(gameId.toString()),
                SID: params.SID,
                _SID: params._SID,
                NAME: params.NAME,
                START_TIME: params.START_TIME,
                timestamp: params.timestamp || Math.floor(Date.now() / 1000)
            };

            // 生成签名
            const sign = this.generateServerSyncSign(syncParams, signKey);

            // 构建完整参数
            const fullParams: ServerSyncParams = {
                ...syncParams,
                sign
            };

            // 发送开服同步请求
            const result = await this.sendServerSyncRequest(fullParams, config);

            logger.info('Mianyou开服同步结果', {
                params: syncParams,
                result
            });

            return result;

        } catch (error) {
            logger.error('Mianyou开服同步异常', error);
            return {
                status: -9,
                msg: '开服同步失败: 服务器内部错误'
            };
        }
    }

    /**
     * 生成开服同步签名
     * 根据文档：将所有参数按a-z升序排序后，将值直接拼接起来后再与密钥拼接，然后md5
     * @param params 参数对象（不包含sign）
     * @param key 签名密钥
     * @returns MD5哈希值（小写）
     */
    private generateServerSyncSign(params: Omit<ServerSyncParams, 'sign'>, key: string): string {
        // 按a-z升序排序参数
        const sortedKeys = Object.keys(params).sort();

        // 拼接所有参数值
        const toSign = sortedKeys.map(key => params[key as keyof typeof params]).join('');

        // 与密钥拼接后MD5
        const data = toSign + key;
        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
    }

    /**
     * 发送开服同步请求
     * @param params 完整参数（包含sign）
     * @param config 渠道配置
     * @returns 同步结果
     */
    private async sendServerSyncRequest(params: ServerSyncParams, config: ChannelConfig): Promise<ServerSyncResult> {
        try {
            // 构建请求URL
            const sdkDomain = config.paymentConfig?.apiUrl;
            const url = `${sdkDomain}/game/center/sync_server`;

            // 构建form-data格式的请求体
            const formData = new URLSearchParams();
            Object.entries(params).forEach(([key, value]) => {
                formData.append(key, value.toString());
            });

            logger.info('发送开服同步请求', {url, params});

            // 发送POST请求
            const response = await axios.post(url, formData, {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                timeout: 10000
            });

            // 解析响应
            const result = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;

            logger.info('开服同步响应', {result});

            return {
                status: result.status || 0,
                msg: result.msg || '未知响应'
            };

        } catch (error) {
            logger.error('发送开服同步请求失败', error);
            return {
                status: -9,
                msg: '网络请求失败'
            };
        }
    }

    /**
     * 便捷的开服同步方法
     * @param serverId 区服序号
     * @param gameServerId 游戏区服ID
     * @param serverName 区服名称
     * @param startTime 开服时间
     * @param config 渠道配置
     * @returns 同步结果
     */
    async openServer(
        serverId: number,
        gameServerId: number | string,
        serverName: string,
        startTime: string,
        config: ChannelConfig
    ): Promise<ServerSyncResult> {
        // 获取游戏ID
        const gameId = config.paymentConfig?.gameId;
        if (!gameId) {
            return {
                status: -2,
                msg: '配置错误: 缺少游戏ID'
            };
        }

        return await this.syncServerOpen({
            GAME_ID: parseInt(gameId.toString()),
            SID: serverId,
            _SID: gameServerId,
            NAME: serverName,
            START_TIME: startTime,
            timestamp: Math.floor(Date.now() / 1000)
        }, config);
    }

}
