// Pure helpers for the /approvals operator surface.
//
// listAudit() returns the raw audit_logs tail, which mixes high-volume rows
// (e.g. printing_press.security_mode.changed, pp_strict_approval_required, and
// the matched approval.request) with low-volume rows we never want to show on
// /approvals at all (agent.create, run, etc.). These helpers shape that tail
// into the "audit context" panel:
//
//   filterApprovalSignal(rows)
//     drops any row whose type isn't tied to the approvals workflow.
//
//   collapseAuditFeed(rows, { windowMs })
//     merges consecutive duplicates by (type, approval_request_id) — or by
//     (type, summary) when no request id is present — into a single entry
//     with { count, first_at, last_at, ids: [auditId,...] }.
//
//   linkPendingRequests(rows, requests)
//     decorates rows with linked_request_id when meta.approval_request_id
//     matches a pending row in requests, so the UI can render a "jump to
//     queue card" chip.

const SIGNAL_TYPES = new Set([
  'approval.request',
  'approval.decision',
  'main_agent.tool.pp_strict_approval_required',
  'main_agent.tool.irreversible_external_approval_required',
  'printing_press.security_mode.changed',
  'main_agent.trust_mode.changed',
]);

const DEFAULT_WINDOW_MS = 5 * 60 * 1000;

function parseMeta(meta) {
  if (!meta) return null;
  if (typeof meta === 'object') return meta;
  try { return JSON.parse(meta); } catch { return null; }
}

function rowApprovalId(row) {
  const meta = parseMeta(row?.meta);
  return meta?.approval_request_id || meta?.approvalRequestId || null;
}

function dedupeKey(row) {
  const approvalId = rowApprovalId(row);
  if (approvalId) return `${row.type}::req=${approvalId}`;
  return `${row.type}::sum=${row.summary || ''}`;
}

function toMs(value) {
  if (value == null) return 0;
  if (typeof value === 'number') return value;
  const t = Date.parse(value);
  return Number.isFinite(t) ? t : 0;
}

export function filterApprovalSignal(rows) {
  if (!Array.isArray(rows)) return [];
  return rows.filter((row) => row && SIGNAL_TYPES.has(row.type));
}

export function collapseAuditFeed(rows, { windowMs = DEFAULT_WINDOW_MS } = {}) {
  if (!Array.isArray(rows) || rows.length === 0) return [];
  // listAudit() returns DESC. Walk in chronological order so the "first" event
  // in a burst is the anchor and later identical events fold into it.
  const ascending = [...rows].sort((a, b) => toMs(a.at) - toMs(b.at));

  const collapsed = [];
  const indexByKey = new Map();

  for (const row of ascending) {
    if (!row) continue;
    const key = dedupeKey(row);
    const at = toMs(row.at);
    const existingIdx = indexByKey.get(key);
    if (existingIdx != null) {
      const anchor = collapsed[existingIdx];
      if (at - toMs(anchor.last_at) <= windowMs) {
        anchor.count += 1;
        anchor.last_at = row.at;
        anchor.ids.push(row.id);
        // Always keep the freshest status visible (e.g. pending → approved).
        if (row.status) anchor.status = row.status;
        continue;
      }
    }
    const entry = {
      ...row,
      meta: parseMeta(row.meta),
      count: 1,
      first_at: row.at,
      last_at: row.at,
      ids: [row.id],
      linked_request_id: rowApprovalId(row),
    };
    collapsed.push(entry);
    indexByKey.set(key, collapsed.length - 1);
  }

  // Restore DESC ordering by last_at so the most recent burst sits on top.
  collapsed.sort((a, b) => toMs(b.last_at) - toMs(a.last_at));
  return collapsed;
}

export function linkPendingRequests(rows, requests) {
  if (!Array.isArray(rows) || rows.length === 0) return rows || [];
  const pendingIds = new Set();
  if (Array.isArray(requests)) {
    for (const req of requests) {
      if (req && req.status === 'pending' && req.id) pendingIds.add(req.id);
    }
  }
  return rows.map((row) => {
    const linked = row.linked_request_id || rowApprovalId(row);
    if (linked && pendingIds.has(linked)) {
      return { ...row, linked_request_id: linked, linked_pending: true };
    }
    return { ...row, linked_request_id: linked, linked_pending: false };
  });
}

export const __test__ = { SIGNAL_TYPES, DEFAULT_WINDOW_MS, dedupeKey, parseMeta, rowApprovalId };
