/**
 * 签名验证工具类
 * 用于处理不同渠道的签名验证
 */

const CryptoJS = require("crypto-js");
import QuickAsy from "./quickAsy";
import SnsSigCheck from "./snsSigCheck";
const logger = require("../utils/log");

export class SignatureVerifier {
  /**
   * 验证通用MD5签名
   * @param data 请求数据
   * @param secretKey 密钥
   * @param excludeFields 需要排除的字段，默认为["sign"]
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verifyMD5Sign(
    data: any,
    secretKey: string,
    excludeFields: string[] = ["sign","appId","timestamp"]
  ): boolean {
    const sign = data.sign;
    const signData = Object.keys(data)
      .sort()
      .filter((key) => !excludeFields.includes(key));

    const signStr = signData.map((key) => `${data[key]}`).join("") + secretKey;
    const newSign = CryptoJS.MD5(signStr).toString();

    logger.info("MD5签名验证:", {
      signStr: signStr,
      newSign: newSign,
      sign: sign,
    });

    return sign === newSign;
  }

  /**
   * 验证三粒支付签名
   * @param data 请求数据
   * @param secretKey 密钥
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verifySanLiSign(data: any, secretKey: string): boolean {
    const sign = data.sign;
    const signData = Object.keys(data)
      .sort()
      .filter((key) => key !== "sign");

    const signStr =
      signData.map((key) => `${key}=${data[key]}`).join("&") +
      "&key=" +
      secretKey;

    const newSign = CryptoJS.MD5(signStr).toString();

    logger.info("三粒支付签名验证:", {
      signStr: signStr,
      newSign: newSign,
      sign: sign,
    });

    return sign === newSign;
  }

  /**
   * 验证360支付签名
   * @param data 请求数据
   * @param secretKey 密钥
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verify360Sign(data: any, secretKey: string): boolean {
    const sign = data.sign;
    const signData = Object.keys(data)
      .sort()
      .filter((key) => key !== "sign");

    const signStr = signData.map((key) => `${data[key]}`).join("") + secretKey;
    const newSign = CryptoJS.MD5(signStr).toString();

    logger.info("360支付签名验证:", {
      signStr: signStr,
      newSign: newSign,
      sign: sign,
    });

    return sign === newSign;
  }

  /**
   * 验证快手支付签名
   * @param data 请求数据
   * @param md5Key 密钥
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verifyQuickSign(data: any, md5Key: string): boolean {
    const md5Sign = data.md5Sign;
    const verifySignData = QuickAsy.getSign(data, md5Key);

    logger.info("快手支付签名验证:", {
      verifySignData: verifySignData,
      md5Sign: md5Sign,
    });

    return verifySignData === md5Sign;
  }

  /**
   * 验证QQ支付签名
   * @param method HTTP方法，如"GET"
   * @param path 请求路径，如"/api/qqCallback"
   * @param signData 签名数据
   * @param key 密钥
   * @param sig 签名
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verifyQQSign(
    method: string,
    path: string,
    signData: string[],
    key: string,
    sig: string
  ): boolean {
    return SnsSigCheck.verifySig(method, path, signData, key, sig);
  }

  /**
   * 创建QQ支付签名
   * @param method HTTP方法，如"GET"
   * @param path 请求路径
   * @param params 参数
   * @param key 密钥
   * @returns 签名
   */
  static createQQSign(
    method: string,
    path: string,
    params: any,
    key: string
  ): string {
    return SnsSigCheck.makeSig(method, path, params, key);
  }

  /**
   * 验证晴天SDK签名
   * 签名在请求头 X-Platform-Sign 中
   * 格式: key1=value1&key2=value2&...&key=SECRET (按键名升序排序，不urlencode)
   * @param data 请求body数据
   * @param secretKey 密钥
   * @param headerSign 请求头中的签名值
   * @returns 验证结果
   */
  static verifyQingtianSign(data: any, secretKey: string, headerSign: string): boolean {
    const sortedKeys = Object.keys(data)
        .filter((key) => key !== "sign")
        .sort();

    const pairs = sortedKeys.map((key) => {
      const val = data[key] == null ? "" : String(data[key]);
      return `${key}=${val}`;
    });

    const signStr = pairs.join("&") + "&key=" + secretKey;
    const newSign = CryptoJS.MD5(signStr).toString();

    logger.info("晴天SDK签名验证:", {
      signStr,
      newSign,
      headerSign,
    });

    return newSign === headerSign;
  }

  /**
   * 验证4399签名
   * @param data 请求数据
   * @param secretKey 密钥
   * @returns 验证结果，true为验证通过，false为验证失败
   */
  static verify4399Sign(data: any, secretKey: string): boolean {
    const sign = data.sign;
    const signData = Object.keys(data)
      .sort()
      .filter(
        (key) =>
          key !== "sign" &&
          key !== "channel_id" &&
          key !== "ext" &&
          key !== "gameMoney" &&
          key !== "is_new" && 
          key !== "test"
      );

    // const signStr =
    //   signData
    //     .map((key) => `${key}` + "=" + decodeURIComponent(data[key]))
    //     .join("") + secretKey;
    const excludeDecodeKeys = ["userName"];
    const signStr =
      signData
        .map((key) => {
          const value = excludeDecodeKeys.includes(key)
            ? data[key]
            : decodeURIComponent(data[key]);
          return `${encodeURIComponent(key)}=${value}`;
        })
        .join("") + secretKey;
    const newSign = CryptoJS.MD5(signStr).toString();

    logger.info("4399签名验证:", {
      signData: signData,
      signStr: signStr,
      newSign: newSign,
      sign: sign,
    });

    return sign === newSign;
  }
}
