/**
 * One-shot backfill for Secret.keyNames on startup.
 *
 * `keyNames` is populated on every write path going forward, but rows that
 * pre-date the column (or that were migrated to a non-plaintext backend
 * before the column existed) carry an empty array. Without this we'd show
 * `KEYS: -` in `mcpctl get secrets` until each row is individually
 * described — confusing UX.
 *
 * Run once per startup. Idempotent: any row whose keyNames is non-empty is
 * skipped. Errors are non-fatal — the lazy backfill in
 * `SecretService.getById` will retry per-row on the next describe.
 */
import type { PrismaClient, Secret } from '@prisma/client';
import type { SecretService } from '../services/secret.service.js';

export interface BackfillResult {
  scanned: number;
  populated: number;
  failed: number;
}

export async function backfillSecretKeyNames(
  prisma: PrismaClient,
  secretService: SecretService,
  log?: { info: (m: string) => void; warn: (m: string) => void },
): Promise<BackfillResult> {
  const out: BackfillResult = { scanned: 0, populated: 0, failed: 0 };

  // Find rows that need backfill: empty keyNames AND empty data (i.e. the
  // values live in a remote backend, so we can't derive keys without a
  // backend read). Plaintext-backed rows are handled by the lazy path
  // (cheap — no IO).
  const rows = await prisma.secret.findMany({
    where: {
      keyNames: { equals: [] },
      data: { equals: {} },
    },
    select: { id: true, name: true, backendId: true, data: true, externalRef: true, keyNames: true, version: true, createdAt: true, updatedAt: true },
  });
  out.scanned = rows.length;
  if (rows.length === 0) return out;

  // Sequential rather than parallel — being kind to the upstream backend on
  // first cold start. 9 secrets * ~50ms = 0.5s; fine.
  for (const row of rows) {
    try {
      const data = await secretService.resolveData(row as Secret);
      const keys = Object.keys(data).sort();
      if (keys.length === 0) continue;
      await prisma.secret.update({ where: { id: row.id }, data: { keyNames: keys } });
      out.populated++;
    } catch (err) {
      out.failed++;
      if (log !== undefined) {
        log.warn(`secret-keynames-backfill: ${row.name}: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
  }
  if (log !== undefined && out.populated > 0) {
    log.info(`secret-keynames-backfill: populated ${String(out.populated)}/${String(out.scanned)} secret(s)`);
  }
  return out;
}
