// lib/hail/quarterly-review.js — the ongoing Managed Layer quarterly review.
//
// A quarterly review is a SEPARATE process-engine case (hail-quarterly-review
// definition) linked to its engagement by project (engagement↔project is 1:1).
// It produces a DRY-RUN delta setup package that routes through the SAME
// approval → apply path as the lifecycle: the reconfig-approval gate flips the
// delta package to 'approved' (via lib/hail/review-gates.js), then the operator
// runs the existing applier (lib/hail/setup-applier.js) — which idempotently
// no-ops already-applied items and provisions only the new ones.
//
// This module NEVER writes process_cases.* (the engine owns case state) and
// never mutates runtime config (the applier does, through its existing gates).

import { getDb, nowIso } from '../db.js';
import { appendAudit } from '../runtime.js';
import { startCase, listCases } from '../process/engine.js';
import { getEngagement } from './engagements.js';
import { getSetupPackage, buildSetupPackage } from './setup-package.js';
import { HAIL_QUARTERLY_REVIEW_WORKFLOW_SLUG } from './constants.js';

// Start a quarterly review for an engagement that has reached the Managed Layer.
export function startQuarterlyReview(engagement_id, { created_by_user_id = null, title = null } = {}) {
  const engagement = getEngagement(engagement_id);
  if (!engagement) throw new Error('startQuarterlyReview: engagement not found');
  if (engagement.current_stage !== 'managed_layer') {
    const err = new Error('startQuarterlyReview: engagement is not in the Managed Layer yet');
    err.code = 'not_managed_layer';
    throw err;
  }
  const caseRow = startCase({
    definition_slug: HAIL_QUARTERLY_REVIEW_WORKFLOW_SLUG,
    project_id: engagement.project_id,
    title: title || `HAIL quarterly review — ${engagement.principal_name}`,
    created_by_user_id,
  });
  appendAudit({
    type: 'hail.quarterly.start',
    summary: `HAIL quarterly review started for ${engagement.principal_name}`,
    status: 'ok',
    meta: { engagement_id, process_case_id: caseRow.id },
  });
  return caseRow;
}

// Quarterly-review cases for an engagement (matched by its project).
export function listQuarterlyReviews(engagement_id) {
  const engagement = getEngagement(engagement_id);
  if (!engagement?.project_id) return [];
  return listCases({ project_id: engagement.project_id, definition_slug: HAIL_QUARTERLY_REVIEW_WORKFLOW_SLUG, limit: 50 });
}

// Map a stored setup-package ledger item back onto a package-item shape so it can
// be re-proposed in a delta package.
function reproposeItem(item) {
  return {
    type: item.type,
    ref: item.ref,
    risk: item.risk,
    // Default to gated for anything above `low` (safer than under-gating); the
    // applier still enforces per-risk gating regardless.
    requires_approval: item.risk !== 'low',
    spec: item.spec || {},
    rationale: 'Re-proposed from the current configuration.',
  };
}

// Produce a DRY-RUN delta setup package. By default it re-proposes the current
// configuration (so the applier is a safe no-op); pass `items` to add/replace
// the desired delta. Reuses buildSetupPackage → validateSetupPackage (forces
// dry_run, rejects secret values) and supersedes any prior dry-run draft.
export function synthesizeReviewDelta(engagement_id, { items = null } = {}) {
  const engagement = getEngagement(engagement_id);
  if (!engagement) throw new Error('synthesizeReviewDelta: engagement not found');
  const current = getSetupPackage(engagement_id);
  const deltaItems = items || (current?.has_package ? current.items.map(reproposeItem) : []);
  if (deltaItems.length === 0) {
    const err = new Error('synthesizeReviewDelta: no items to propose');
    err.code = 'empty_delta';
    throw err;
  }
  const db = getDb();
  const pkg = buildSetupPackage(db, engagement, { generated_by: 'hail-quarterly-review', items: deltaItems });
  appendAudit({
    type: 'hail.quarterly.delta',
    summary: `HAIL quarterly delta setup package built for ${engagement.principal_name} (${pkg.items} items)`,
    status: 'ok',
    meta: { engagement_id, package_id: pkg.package_id, items: pkg.items },
  });
  return pkg;
}
