import * as crypto from 'crypto';

export class EncryptionService {
  private static readonly ALGORITHM = 'aes-256-cbc';
  private static readonly IV_LENGTH = 16;

  /**
   * 加密数据
   * @param data 待加密数据
   * @param key 加密密钥
   * @returns 加密后的数据
   */
  public static encrypt(data: string, key: string): string {
    try {
      const iv = crypto.randomBytes(this.IV_LENGTH);
      const cipher = crypto.createCipheriv(this.ALGORITHM, Buffer.from(key.padEnd(32, '0').substring(0, 32)), iv);
      let encrypted = cipher.update(data, 'utf8', 'base64');
      encrypted += cipher.final('base64');
      return iv.toString('base64') + ':' + encrypted;
    } catch (error) {
      console.error('Error encrypting data:', error);
      throw new Error('Failed to encrypt data');
    }
  }

  /**
   * 解密数据
   * @param encryptedData 加密的数据
   * @param key 解密密钥
   * @returns 解密后的数据
   */
  public static decrypt(encryptedData: string, key: string): string {
    try {
      const [ivBase64, encryptedText] = encryptedData.split(':');
      const iv = Buffer.from(ivBase64, 'base64');
      const decipher = crypto.createDecipheriv(this.ALGORITHM, Buffer.from(key.padEnd(32, '0').substring(0, 32)), iv);
      let decrypted = decipher.update(encryptedText, 'base64', 'utf8');
      decrypted += decipher.final('utf8');
      return decrypted;
    } catch (error) {
      console.error('Error decrypting data:', error);
      throw new Error('Failed to decrypt data');
    }
  }

  /**
   * 生成加密密钥
   * @param length 密钥长度
   * @returns 加密密钥
   */
  public static generateKey(length: number = 32): string {
    try {
      return crypto.randomBytes(length).toString('hex').substring(0, length);
    } catch (error) {
      console.error('Error generating key:', error);
      throw new Error('Failed to generate key');
    }
  }

  /**
   * 哈希数据
   * @param data 待哈希数据
   * @param algorithm 哈希算法
   * @returns 哈希值
   */
  public static hash(data: string, algorithm: string = 'sha256'): string {
    try {
      const hash = crypto.createHash(algorithm);
      hash.update(data);
      return hash.digest('hex');
    } catch (error) {
      console.error('Error hashing data:', error);
      throw new Error('Failed to hash data');
    }
  }

  /**
   * 生成HMAC
   * @param data 待签名数据
   * @param key 密钥
   * @param algorithm 哈希算法
   * @returns HMAC值
   */
  public static generateHMAC(data: string, key: string, algorithm: string = 'sha256'): string {
    try {
      const hmac = crypto.createHmac(algorithm, key);
      hmac.update(data);
      return hmac.digest('hex');
    } catch (error) {
      console.error('Error generating HMAC:', error);
      throw new Error('Failed to generate HMAC');
    }
  }

  /**
   * 验证HMAC
   * @param data 待验证数据
   * @param hmac 待验证的HMAC值
   * @param key 密钥
   * @param algorithm 哈希算法
   * @returns 是否验证通过
   */
  public static verifyHMAC(data: string, hmac: string, key: string, algorithm: string = 'sha256'): boolean {
    try {
      const calculatedHMAC = this.generateHMAC(data, key, algorithm);
      return crypto.timingSafeEqual(Buffer.from(calculatedHMAC), Buffer.from(hmac));
    } catch (error) {
      console.error('Error verifying HMAC:', error);
      return false;
    }
  }

  /**
   * 生成随机盐
   * @param length 盐长度
   * @returns 随机盐
   */
  public static generateSalt(length: number = 16): string {
    try {
      return crypto.randomBytes(length).toString('hex');
    } catch (error) {
      console.error('Error generating salt:', error);
      throw new Error('Failed to generate salt');
    }
  }

  /**
   * 对密码进行哈希处理
   * @param password 密码
   * @param salt 盐
   * @returns 哈希后的密码
   */
  public static hashPassword(password: string, salt: string = this.generateSalt()): {
    hashedPassword: string;
    salt: string;
  } {
    try {
      const hashedPassword = this.hash(password + salt);
      return {
        hashedPassword,
        salt,
      };
    } catch (error) {
      console.error('Error hashing password:', error);
      throw new Error('Failed to hash password');
    }
  }

  /**
   * 验证密码
   * @param password 密码
   * @param hashedPassword 哈希后的密码
   * @param salt 盐
   * @returns 是否验证通过
   */
  public static verifyPassword(password: string, hashedPassword: string, salt: string): boolean {
    try {
      const calculatedHash = this.hash(password + salt);
      return crypto.timingSafeEqual(Buffer.from(calculatedHash), Buffer.from(hashedPassword));
    } catch (error) {
      console.error('Error verifying password:', error);
      return false;
    }
  }

  /**
   * 生成RSA密钥对
   * @param modulusLength 模数长度
   * @returns RSA密钥对
   */
  public static generateRSAKeyPair(modulusLength: number = 2048): {
    privateKey: string;
    publicKey: string;
  } {
    try {
      const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
        modulusLength,
        publicKeyEncoding: {
          type: 'spki',
          format: 'pem',
        },
        privateKeyEncoding: {
          type: 'pkcs8',
          format: 'pem',
        },
      });
      return {
        privateKey,
        publicKey,
      };
    } catch (error) {
      console.error('Error generating RSA key pair:', error);
      throw new Error('Failed to generate RSA key pair');
    }
  }

  /**
   * 使用RSA公钥加密数据
   * @param data 待加密数据
   * @param publicKey RSA公钥
   * @returns 加密后的数据
   */
  public static rsaEncrypt(data: string, publicKey: string): string {
    try {
      const encrypted = crypto.publicEncrypt(publicKey, Buffer.from(data, 'utf8'));
      return encrypted.toString('base64');
    } catch (error) {
      console.error('Error encrypting data with RSA:', error);
      throw new Error('Failed to encrypt data with RSA');
    }
  }

  /**
   * 使用RSA私钥解密数据
   * @param encryptedData 加密的数据
   * @param privateKey RSA私钥
   * @returns 解密后的数据
   */
  public static rsaDecrypt(encryptedData: string, privateKey: string): string {
    try {
      const decrypted = crypto.privateDecrypt(privateKey, Buffer.from(encryptedData, 'base64'));
      return decrypted.toString('utf8');
    } catch (error) {
      console.error('Error decrypting data with RSA:', error);
      throw new Error('Failed to decrypt data with RSA');
    }
  }

  /**
   * 使用RSA私钥签名数据
   * @param data 待签名数据
   * @param privateKey RSA私钥
   * @param algorithm 哈希算法
   * @returns 签名
   */
  public static rsaSign(data: string, privateKey: string, algorithm: string = 'sha256'): string {
    try {
      const sign = crypto.createSign(algorithm);
      sign.update(data);
      sign.end();
      const signature = sign.sign(privateKey, 'base64');
      return signature;
    } catch (error) {
      console.error('Error signing data with RSA:', error);
      throw new Error('Failed to sign data with RSA');
    }
  }

  /**
   * 使用RSA公钥验证签名
   * @param data 待验证数据
   * @param signature 待验证的签名
   * @param publicKey RSA公钥
   * @param algorithm 哈希算法
   * @returns 是否验证通过
   */
  public static rsaVerify(data: string, signature: string, publicKey: string, algorithm: string = 'sha256'): boolean {
    try {
      const verify = crypto.createVerify(algorithm);
      verify.update(data);
      verify.end();
      return verify.verify(publicKey, signature, 'base64');
    } catch (error) {
      console.error('Error verifying signature with RSA:', error);
      return false;
    }
  }

  /**
   * 加密传输数据
   * @param data 待加密数据
   * @param traceInfo 追踪信息
   * @returns 加密后的传输数据
   */
  public static encryptTransmissionData(
    data: any,
    traceInfo: {
      tenantId: string;
      shopId: string;
      taskId: string;
      traceId: string;
      businessType: 'TOC' | 'TOB';
    }
  ): {
    encryptedData: string;
    iv: string;
    timestamp: string;
    signature: string;
  } {
    try {
      const timestamp = new Date().toISOString();
      const dataToEncrypt = JSON.stringify({
        data,
        traceInfo,
        timestamp,
      });
      
      // 生成临时密钥（实际应用中应该使用安全的密钥管理方案）
      const key = this.generateKey();
      const iv = crypto.randomBytes(this.IV_LENGTH).toString('base64');
      
      // 加密数据
      const encryptedData = this.encrypt(dataToEncrypt, key);
      
      // 生成签名
      const signature = this.generateHMAC(encryptedData, key);
      
      return {
        encryptedData,
        iv,
        timestamp,
        signature,
      };
    } catch (error) {
      console.error('Error encrypting transmission data:', error);
      throw new Error('Failed to encrypt transmission data');
    }
  }

  /**
   * 解密传输数据
   * @param encryptedData 加密的数据
   * @param key 解密密钥
   * @param traceInfo 追踪信息
   * @returns 解密后的数据
   */
  public static decryptTransmissionData(
    encryptedData: string,
    key: string,
    traceInfo: {
      tenantId: string;
      shopId: string;
      taskId: string;
      traceId: string;
      businessType: 'TOC' | 'TOB';
    }
  ): any {
    try {
      const decryptedData = this.decrypt(encryptedData, key);
      const parsedData = JSON.parse(decryptedData);
      
      // 验证追踪信息
      if (
        parsedData.traceInfo.tenantId !== traceInfo.tenantId ||
        parsedData.traceInfo.shopId !== traceInfo.shopId ||
        parsedData.traceInfo.taskId !== traceInfo.taskId ||
        parsedData.traceInfo.traceId !== traceInfo.traceId ||
        parsedData.traceInfo.businessType !== traceInfo.businessType
      ) {
        throw new Error('Invalid trace information');
      }
      
      return parsedData.data;
    } catch (error) {
      console.error('Error decrypting transmission data:', error);
      throw new Error('Failed to decrypt transmission data');
    }
  }

  /**
   * 生成加密方案
   * @param requirements 加密需求
   * @param traceInfo 追踪信息
   * @returns 加密方案
   */
  public static generateEncryptionScheme(
    requirements: {
      dataTypes: string[];
      securityLevel: 'low' | 'medium' | 'high';
      complianceStandards: string[];
    },
    traceInfo: {
      tenantId: string;
      shopId: string;
      taskId: string;
      traceId: string;
      businessType: 'TOC' | 'TOB';
    }
  ): {
    schemeId: string;
    timestamp: string;
    encryptionMethods: Array<{
      dataType: string;
      method: string;
      keyLength: number;
      algorithm: string;
      recommended: boolean;
    }>;
    compliance: {
      standards: string[];
      status: 'compliant' | 'partial' | 'non-compliant';
    };
    implementationGuidelines: string[];
  } {
    try {
      const schemeId = `ENCRYPTION-SCHEME-${Date.now()}`;
      const timestamp = new Date().toISOString();
      const encryptionMethods = [];
      
      // 根据数据类型和安全级别生成加密方法
      for (const dataType of requirements.dataTypes) {
        let method = 'AES-256-CBC';
        let keyLength = 32;
        let algorithm = 'aes-256-cbc';
        
        if (dataType === 'password') {
          method = 'PBKDF2';
          keyLength = 32;
          algorithm = 'pbkdf2-sha256';
        } else if (dataType === 'token') {
          method = 'HMAC';
          keyLength = 32;
          algorithm = 'hmac-sha256';
        } else if (dataType === 'sensitive') {
          method = 'RSA-2048';
          keyLength = 2048;
          algorithm = 'rsa';
        }
        
        encryptionMethods.push({
          dataType,
          method,
          keyLength,
          algorithm,
          recommended: true,
        });
      }
      
      // 检查合规性
      const complianceStandards = requirements.complianceStandards;
      const compliantStandards = [];
      
      for (const standard of complianceStandards) {
        if (standard === 'GDPR' || standard === 'PCI-DSS' || standard === 'HIPAA') {
          compliantStandards.push(standard);
        }
      }
      
      let complianceStatus: 'compliant' | 'partial' | 'non-compliant' = 'compliant';
      if (compliantStandards.length < complianceStandards.length) {
        complianceStatus = 'partial';
      } else if (compliantStandards.length === 0) {
        complianceStatus = 'non-compliant';
      }
      
      // 生成实现指南
      const implementationGuidelines = [
        'Use HTTPS for all data transmission',
        'Implement proper key management',
        'Rotate encryption keys regularly',
        'Use secure random number generators',
        'Implement proper error handling',
        'Regularly audit encryption implementation',
      ];
      
      return {
        schemeId,
        timestamp,
        encryptionMethods,
        compliance: {
          standards: compliantStandards,
          status: complianceStatus,
        },
        implementationGuidelines,
      };
    } catch (error) {
      console.error('Error generating encryption scheme:', error);
      throw new Error('Failed to generate encryption scheme');
    }
  }
}
