import crypto from 'crypto';

function randomHex(bytes = 32): string {
  return crypto.randomBytes(bytes).toString('hex');
}

function randomPassword(length = 16): string {
  // Generate password meeting CML policy: 12+ chars, uppercase, lowercase, digit
  const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  const lower = 'abcdefghijklmnopqrstuvwxyz';
  const digits = '0123456789';
  // Avoid chars that break Docker Compose .env or YAML:
  // $=var expansion, #=comment, !=bash history, %=printf,
  // &=YAML anchor, *=YAML alias, :=YAML key-value, []=YAML flow
  const special = '@_-+=';
  const all = upper + lower + digits + special;

  // Ensure at least one of each required class
  const required = [
    upper[crypto.randomInt(upper.length)],
    lower[crypto.randomInt(lower.length)],
    digits[crypto.randomInt(digits.length)],
    special[crypto.randomInt(special.length)],
  ];

  // Fill remaining with random chars
  const remaining = Array.from({ length: length - required.length }, () =>
    all[crypto.randomInt(all.length)]
  );

  // Shuffle
  const chars = [...required, ...remaining];
  for (let i = chars.length - 1; i > 0; i--) {
    const j = crypto.randomInt(i + 1);
    [chars[i], chars[j]] = [chars[j], chars[i]];
  }

  return chars.join('');
}

export interface InstanceSecrets {
  postgresPassword: string;
  redisPassword: string;
  jwtAccessSecret: string;
  jwtRefreshSecret: string;
  jwtInviteSecret: string;
  // Added 2026-04-12 (P2-2): Changemaker Lite now requires distinct secrets for
  // Gitea SSO cookies and service-account password derivation — the old
  // JWT_ACCESS_SECRET fallback was removed. New instances provisioned by CCP
  // must receive both to boot.
  giteaSsoSecret: string;
  servicePasswordSalt: string;
  encryptionKey: string;
  initialAdminPassword: string;
  nocodbAdminPassword: string;
  grafanaAdminPassword: string;
  listmonkAdminPassword: string;
  listmonkApiToken: string;
  giteaAdminPassword: string;
  n8nEncryptionKey: string;
  gancioAdminPassword: string;
  vaultwardenAdminToken: string;
  jitsiAppSecret: string;
  jitsiJicofoAuthPassword: string;
  jitsiJvbAuthPassword: string;
  rocketchatAdminPassword: string;
  mongoRootPassword: string;
}

export function generateSecrets(adminEmail: string): InstanceSecrets & { adminEmail: string } {
  return {
    adminEmail,
    postgresPassword: randomHex(16),
    redisPassword: randomHex(16),
    jwtAccessSecret: randomHex(32),
    jwtRefreshSecret: randomHex(32),
    jwtInviteSecret: randomHex(32),
    giteaSsoSecret: randomHex(32),
    servicePasswordSalt: randomHex(32),
    encryptionKey: randomHex(32),
    initialAdminPassword: randomPassword(16),
    nocodbAdminPassword: randomPassword(16),
    grafanaAdminPassword: randomPassword(16),
    listmonkAdminPassword: randomPassword(16),
    listmonkApiToken: randomHex(16),
    giteaAdminPassword: randomPassword(16),
    n8nEncryptionKey: randomHex(32),
    gancioAdminPassword: randomPassword(16),
    vaultwardenAdminToken: randomHex(32),
    jitsiAppSecret: randomHex(32),
    jitsiJicofoAuthPassword: randomHex(16),
    jitsiJvbAuthPassword: randomHex(16),
    rocketchatAdminPassword: randomPassword(16),
    mongoRootPassword: randomHex(16),
  };
}
