import { Injectable, Logger } from '@nestjs/common';
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
import { PrismaService } from '../../infrastructure/database/prisma.service';

const ALGO = 'aes-256-gcm';
const FALLBACK_KEY = 'zhixi-secret-master-key-2026-32b!!';

function getMasterKey(): Buffer {
  const envKey = process.env.SECRET_MASTER_KEY;
  if (!envKey || envKey === FALLBACK_KEY) {
    const msg = 'SECRET_MASTER_KEY 使用的是默认值，生产环境请务必设置环境变量 SECRET_MASTER_KEY';
    if (process.env.NODE_ENV === 'production') {
      console.error(`\n🔴 严重警告: ${msg}\n`);
    } else {
      console.warn(`\n⚠️  警告: ${msg}\n`);
    }
  }
  const key = (envKey || FALLBACK_KEY).padEnd(32, '0').slice(0, 32);
  return Buffer.from(key);
}

const KEY = getMasterKey();
const IV_LEN = 16;
const TAG_LEN = 16;

@Injectable()
export class SecretService {
  private readonly logger = new Logger(SecretService.name);

  constructor(private readonly prisma: PrismaService) {}

  encrypt(plaintext: string): string {
    const iv = randomBytes(IV_LEN);
    const cipher = createCipheriv(ALGO, KEY, iv);
    const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
    const tag = cipher.getAuthTag();
    return Buffer.concat([iv, tag, encrypted]).toString('base64');
  }

  decrypt(encoded: string): string {
    const buf = Buffer.from(encoded, 'base64');
    const iv = buf.slice(0, IV_LEN);
    const tag = buf.slice(IV_LEN, IV_LEN + TAG_LEN);
    const encrypted = buf.slice(IV_LEN + TAG_LEN);
    const decipher = createDecipheriv(ALGO, KEY, iv);
    decipher.setAuthTag(tag);
    return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8');
  }

  async create(name: string, provider: string, value: string, expiresAt?: string) {
    const encrypted = this.encrypt(value);
    const maskLast4 = value.slice(-4);
    return this.prisma.secretRecord.create({
      data: { name, provider, encrypted, maskLast4, expiresAt: expiresAt ? new Date(expiresAt) : null },
      select: { id: true, name: true, provider: true, maskLast4: true, status: true, expiresAt: true, createdAt: true },
    });
  }

  async getDecrypted(name: string, accessedBy: string): Promise<string | null> {
    const record = await this.prisma.secretRecord.findUnique({ where: { name } });
    if (!record || record.status !== 'active') return null;
    await this.prisma.secretAccessLog.create({ data: { secretId: record.id, secretName: name, accessedBy } }).catch(() => {});
    return this.decrypt(record.encrypted);
  }

  async list() { return this.prisma.secretRecord.findMany({ select: { id: true, name: true, provider: true, maskLast4: true, status: true, expiresAt: true, createdAt: true }, orderBy: { createdAt: 'desc' } }) }

  async delete(id: string) { await this.prisma.secretRecord.delete({ where: { id } }) }

  async accessLogs(limit = 50) { return this.prisma.secretAccessLog.findMany({ orderBy: { createdAt: 'desc' }, take: limit }) }
}
