import crypto from 'crypto';
import store from 'napcat-common/src/store';
import type { WebUiCredentialJson, WebUiCredentialInnerJson } from '@/napcat-webui-backend/src/types';
export class AuthHelper {
  private static readonly secretKey = process.env['NAPCAT_WEBUI_JWT_SECRET_KEY'] || Math.random().toString(36).slice(2);

  public static getSecretKey (): string {
    return AuthHelper.secretKey;
  }

  /**
     * 签名凭证方法。
     * @param hash 待签名的凭证字符串。
     * @returns 签名后的凭证对象。
     */
  public static signCredential (hash: string): WebUiCredentialJson {
    const innerJson: WebUiCredentialInnerJson = {
      CreatedTime: Date.now(),
      HashEncoded: hash,
    };
    const jsonString = JSON.stringify(innerJson);
    const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');
    return { Data: innerJson, Hmac: hmac };
  }

  /**
     * 检查凭证是否被篡改的方法。
     * @param credentialJson 凭证的JSON对象。
     * @returns 布尔值，表示凭证是否有效。
     */
  public static checkCredential (credentialJson: WebUiCredentialJson): boolean {
    try {
      const jsonString = JSON.stringify(credentialJson.Data);
      const calculatedHmac = crypto
        .createHmac('sha256', AuthHelper.secretKey)
        .update(jsonString, 'utf8')
        .digest('hex');
      return calculatedHmac === credentialJson.Hmac;
    } catch (_error) {
      return false;
    }
  }

  /**
     * 验证凭证在1小时内有效且token与原始token相同。
     * @param token 待验证的原始token。
     * @param credentialJson 已签名的凭证JSON对象。
     * @returns 布尔值，表示凭证是否有效且token匹配。
     */
  public static validateCredentialWithinOneHour (token: string, credentialJson: WebUiCredentialJson): boolean {
    // 首先检查凭证是否被篡改
    const isValid = AuthHelper.checkCredential(credentialJson);
    if (!isValid) {
      return false;
    }

    // 检查凭证是否在黑名单中
    if (AuthHelper.isCredentialRevoked(credentialJson)) {
      return false;
    }

    const currentTime = Date.now() / 1000;
    const createdTime = credentialJson.Data.CreatedTime;
    const timeDifference = currentTime - createdTime;
    return timeDifference <= 3600 && credentialJson.Data.HashEncoded === AuthHelper.generatePasswordHash(token);
  }

  /**
     * 注销指定的Token凭证
     * @param credentialJson 凭证JSON对象
     * @returns void
     */
  public static revokeCredential (credentialJson: WebUiCredentialJson): void {
    const jsonString = JSON.stringify(credentialJson.Data);
    const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');

    // 将已注销的凭证添加到黑名单中，有效期1小时
    store.set(`revoked:${hmac}`, true, 3600);
  }

  /**
     * 检查凭证是否已被注销
     * @param credentialJson 凭证JSON对象
     * @returns 布尔值，表示凭证是否已被注销
     */
  public static isCredentialRevoked (credentialJson: WebUiCredentialJson): boolean {
    const jsonString = JSON.stringify(credentialJson.Data);
    const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');

    return store.exists(`revoked:${hmac}`) > 0;
  }

  /**
     * 生成密码Hash
     * @param password 密码
     * @returns 生成的Hash值
     */
  public static generatePasswordHash (password: string): string {
    return crypto.createHash('sha256').update(password + '.napcat').digest().toString('hex');
  }

  /**
     * 对比密码和Hash值
     * @param password 密码
     * @param hash Hash值
     * @returns 布尔值，表示密码是否匹配Hash值
     */
  public static comparePasswordHash (password: string, hash: string): boolean {
    return this.generatePasswordHash(password) === hash;
  }
}
