import db from '../../config/database';
import { logger } from '../../utils/logger';
import { LogMaskingService } from '../security/LogMaskingService';
import { SemanticLogService } from '../telemetry/SemanticLogService';
import https from 'https';

/**
 * [BIZ_INF_106] 租户域名证书过期自动预警 (SSL Watch)
 * @description 核心逻辑：定时扫描租户配置的域名，获取其 SSL 证书到期时间。
 * 当到期时间小于 15 天时，自动生成预警并归档至语义日志中心。
 * 通过 [LogMaskingService] 屏蔽域名 PII。
 */
export class CertsMonitorService {
  private static readonly ALERT_THRESHOLD_DAYS = 15; // 预警阈值：15天
  private static readonly CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 检查间隔：24小时

  /**
   * 初始化定时任务
   */
  static async init() {
    this.runCheck();
    setInterval(() => this.runCheck(), this.CHECK_INTERVAL_MS);
    logger.info(`[SSLWatch] Certificate monitor initialized (Alert threshold: ${this.ALERT_THRESHOLD_DAYS} days)`);
  }

  /**
   * 执行证书扫描
   */
  private static async runCheck() {
    try {
      // 1. 获取所有活跃租户的自定义域名 (模拟从 cf_tenants 表中获取)
      const tenants = await db('cf_tenants').select('id', 'custom_domain').whereNotNull('custom_domain');

      for (const tenant of tenants) {
        if (!tenant.custom_domain) continue;

        const expirationDate = await this.getCertificateExpirationDate(tenant.custom_domain);
        if (!expirationDate) continue;

        const daysRemaining = Math.ceil((expirationDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24));

        if (daysRemaining <= this.ALERT_THRESHOLD_DAYS) {
          await this.reportExpiration(tenant.id, tenant.custom_domain, daysRemaining, expirationDate);
        }
      }
    } catch (err: any) {
      logger.error(`[SSLWatch] Scan failed: ${err.message}`);
    }
  }

  /**
   * 获取证书过期日期 (通过 HTTPS 请求获取证书)
   */
  private static async getCertificateExpirationDate(domain: string): Promise<Date | null> {
    return new Promise((resolve) => {
      const options = {
        hostname: domain,
        port: 443,
        method: 'GET',
        rejectUnauthorized: false, // 允许自签名或过期证书以便检测
      };

      const req = https.request(options, (res) => {
        const cert = (res.socket as any).getPeerCertificate();
        if (cert && cert.valid_to) {
          resolve(new Date(cert.valid_to));
        } else {
          resolve(null);
        }
      });

      req.on('error', () => resolve(null));
      req.end();
    });
  }

  /**
   * 上报预警信息
   */
  private static async reportExpiration(tenantId: string, domain: string, daysRemaining: number, expirationDate: Date) {
    const maskedDomain = LogMaskingService.maskData(domain);
    const message = `🚨 SSL Certificate Expiration Warning: Domain \`${maskedDomain}\` (Tenant: ${tenantId}) will expire in ${daysRemaining} days (on ${expirationDate.toISOString()}). Please renew the certificate immediately.`;
    
    await SemanticLogService.logSemantic(message, 'ERROR', 'SECURITY_MONITOR');
    logger.error(`[SSLWatch] Certificate for domain ${maskedDomain} is expiring soon.`);
  }
}
