import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';

const ALGORITHM = 'aes-256-gcm';
const IV_LENGTH = 12; // GCM 推荐 12 字节 IV
const KEY_LENGTH = 32; // 256-bit
const KMS_KEY_VERSION = 1; // MVP 阶段固定 v1；密钥轮转时累加

/**
 * env 值加密 / 解密服务（AES-GCM）
 *
 * MVP 降级方案（07-api §8 / 06 §2.4）：
 * master key 从 env INTERNAL_APP_ENV_MASTER_KEY 读取，scrypt 拉伸到 32 字节；
 * V2 升级到云 KMS 时替换本服务实现，DB schema 不变（kmsKeyVersion 字段已预留）。
 *
 * 存储格式：
 *   value_encrypted = ciphertext || authTag  (concat)
 *   value_iv        = iv (12 bytes)
 *   kms_key_version = 1
 */
@Injectable()
export class InternalAppEnvCryptoService {
  private readonly logger = new Logger(InternalAppEnvCryptoService.name);
  private readonly key: Buffer;

  private readonly keyMissing: boolean;

  constructor(private readonly config: ConfigService) {
    const masterKey = this.config.get<string>('INTERNAL_APP_ENV_MASTER_KEY');
    this.keyMissing = !masterKey || masterKey === '__GENERATE_RANDOM__';
    if (this.keyMissing) {
      const msg =
        'INTERNAL_APP_ENV_MASTER_KEY 未设置或仍是占位 — env 加密能力关闭';
      if (process.env.NODE_ENV === 'production') {
        // 生产硬失败：避免数据被假密钥加密入库后永久无法解密
        throw new Error(msg);
      }
      this.logger.warn(`${msg}（非生产环境，开发期容忍但 encrypt/decrypt 仍会拒绝服务）`);
    }
    const salt = 'internal-app-platform-v1';
    this.key = scryptSync(masterKey ?? 'placeholder-not-for-prod', salt, KEY_LENGTH);
  }

  private assertKeyConfigured(): void {
    if (this.keyMissing) {
      throw new Error('INTERNAL_APP_ENV_MASTER_KEY_missing');
    }
  }

  /**
   * 加密明文 → { encrypted, iv, kmsKeyVersion }
   */
  encrypt(plaintext: string): {
    encrypted: Buffer;
    iv: Buffer;
    kmsKeyVersion: number;
  } {
    this.assertKeyConfigured();
    const iv = randomBytes(IV_LENGTH);
    const cipher = createCipheriv(ALGORITHM, this.key, iv);
    const ciphertext = Buffer.concat([
      cipher.update(plaintext, 'utf8'),
      cipher.final(),
    ]);
    const authTag = cipher.getAuthTag();
    return {
      encrypted: Buffer.concat([ciphertext, authTag]),
      iv,
      kmsKeyVersion: KMS_KEY_VERSION,
    };
  }

  /**
   * 解密 { encrypted, iv } → 明文
   * encrypted 末尾 16 字节是 authTag（GCM 标准）
   */
  decrypt(encrypted: Buffer, iv: Buffer, _kmsKeyVersion: number): string {
    this.assertKeyConfigured();
    const AUTH_TAG_LENGTH = 16;
    const ciphertext = encrypted.subarray(0, encrypted.length - AUTH_TAG_LENGTH);
    const authTag = encrypted.subarray(encrypted.length - AUTH_TAG_LENGTH);

    const decipher = createDecipheriv(ALGORITHM, this.key, iv);
    decipher.setAuthTag(authTag);
    const plaintext = Buffer.concat([
      decipher.update(ciphertext),
      decipher.final(),
    ]);
    return plaintext.toString('utf8');
  }

  /** 生成 valuePreview：前 4 字符 + '****'，用于 env list 不泄漏明文（07-api §3.4.1） */
  maskValue(plaintext: string): string {
    if (plaintext.length <= 4) return '****';
    return `${plaintext.slice(0, 4)}****`;
  }
}
