import * as crypto from 'crypto';
import { logger } from '../../utils/logger';

/**
 * [CORE_SEC_07] 全链路 mTLS 强制加密引擎
 * @description 模拟分布式节点间的双向 TLS 握手与证书校验，确保内部通信绝对安全
 */
export class mTLSEngine {
  private static CA_CERT = '---BEGIN CERTIFICATE--- CRAWLFUL_ROOT_CA ---END CERTIFICATE---';

  /**
   * 生成临时节点证书 (模拟)
   */
  static generateNodeCert(nodeId: string) {
    return {
      nodeId,
      cert: `---BEGIN CERTIFICATE--- ${nodeId}_CERT ---END CERTIFICATE---`,
      issuedAt: Date.now(),
      expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000,
      fingerprint: crypto.createHash('sha256').update(nodeId).digest('hex')
    };
  }

  /**
   * 校验对端证书
   */
  static verifyPeerCert(cert: any): boolean {
    if (!cert || !cert.fingerprint) {
      logger.error('[mTLS] Missing peer certificate');
      return false;
    }

    // 1. 模拟 CA 签名校验
    const isValidSignature = cert.cert.includes('---BEGIN CERTIFICATE---');
    if (!isValidSignature) {
      logger.error(`[mTLS] Invalid certificate signature from node ${cert.nodeId}`);
      return false;
    }

    // 2. 模拟指纹校验
    const expectedFingerprint = crypto.createHash('sha256').update(cert.nodeId).digest('hex');
    if (cert.fingerprint !== expectedFingerprint) {
      logger.error(`[mTLS] Fingerprint mismatch for node ${cert.nodeId}`);
      return false;
    }

    // 3. 校验过期时间
    if (Date.now() > cert.expiresAt) {
      logger.error(`[mTLS] Certificate expired for node ${cert.nodeId}`);
      return false;
    }

    logger.debug(`[mTLS] Successfully verified node ${cert.nodeId}`);
    return true;
  }

  /**
   * 强制执行 mTLS 校验的装饰器 (模拟)
   */
  static secureCall(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      const context = args[0]; // 假设第一个参数包含安全上下文
      if (!mTLSEngine.verifyPeerCert(context?.peerCert)) {
        throw new Error(`[mTLS] Forbidden: Secure call to ${propertyKey} failed verification`);
      }
      return originalMethod.apply(this, args);
    };

    return descriptor;
  }
}
