/**
 * submit_review eligibility for ReportResolver / LifecycleGovernor reconcile.
 */

import {
  parseMarkdownFrontmatter,
  resolveReportTaskId,
  resolveReportTaskIdFromContent,
  strField,
} from "./frontmatter.ts";

export type SubmitReviewSkipReason =
  | "reconciled"
  | "eligible"
  | "skipped_archived"
  | "skipped_not_active"
  | "skipped_not_done"
  | "skipped_auto"
  | "skipped_duplicate"
  | "skipped_sender"
  | "skipped_no_task"
  | "skipped_governance"
  | "skipped_observation"
  | "skipped_rework"
  | "skipped_late_intake"
  | "skipped_yaml_fallback"
  | "admin_attention"
  | "skipped_other";

export type ReconcileSummaryCounters = {
  scanned: number;
  eligible: number;
  reconciled: number;
  skipped_archived: number;
  skipped_not_active: number;
  skipped_not_done: number;
  skipped_auto: number;
  skipped_duplicate: number;
  skipped_sender: number;
  skipped_no_task: number;
  skipped_rework: number;
  skipped_late_intake: number;
  admin_attention: number;
  skipped_other: number;
};

export function emptyReconcileSummary(): ReconcileSummaryCounters {
  return {
    scanned: 0,
    eligible: 0,
    reconciled: 0,
    skipped_archived: 0,
    skipped_not_active: 0,
    skipped_not_done: 0,
    skipped_auto: 0,
    skipped_duplicate: 0,
    skipped_sender: 0,
    skipped_no_task: 0,
    skipped_rework: 0,
    skipped_late_intake: 0,
    admin_attention: 0,
    skipped_other: 0,
  };
}

export function recordReconcileSkip(
  counters: ReconcileSummaryCounters,
  reason: SubmitReviewSkipReason,
): void {
  if (reason === "reconciled") {
    counters.reconciled += 1;
    return;
  }
  if (reason === "eligible") {
    counters.eligible += 1;
    return;
  }
  const key = reason as keyof ReconcileSummaryCounters;
  if (key in counters && key !== "scanned") {
    counters[key] += 1;
    return;
  }
  counters.skipped_other += 1;
}

export function formatPmToAdminReconcileSummary(
  counters: ReconcileSummaryCounters,
): string {
  return (
    `[LifecycleGovernor] PM→ADMIN reconcile summary: ` +
    `scanned=${counters.scanned} eligible=${counters.eligible} reconciled=${counters.reconciled} ` +
    `skipped_archived=${counters.skipped_archived} skipped_not_done=${counters.skipped_not_done} ` +
    `skipped_auto=${counters.skipped_auto} skipped_duplicate=${counters.skipped_duplicate}`
  );
}

export function formatSkipSummaryLines(
  skipCounts: Map<string, number>,
): string {
  if (!skipCounts.size) return "";
  const parts = [...skipCounts.entries()]
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([k, n]) => `${k}=${n}`);
  return `[ReportResolver] skip summary: ${parts.join(" ")}`;
}

export function isAutoGeneratedReciprocalReport(raw: string): boolean {
  return /Auto-generated reciprocal report|ReportGate.*自动补写/i.test(raw);
}

export { isAutoPmFinalSummaryReport } from "./selectCanonicalPmFinalReport.ts";

export function reportStatusDone(reportFm: Record<string, unknown>): boolean {
  if (
    reportFm.valid === false ||
    String(reportFm.valid ?? "").trim().toLowerCase() === "false" ||
    Boolean(strField(reportFm, "invalidated_by")) ||
    Boolean(strField(reportFm, "superseded_by"))
  ) {
    return false;
  }
  const st = strField(reportFm, "status").toLowerCase();
  return st === "done" || st === "completed";
}

export function reportNeedsAdminAttention(
  reportFm: Record<string, unknown>,
): boolean {
  const st = strField(reportFm, "status").toLowerCase();
  return st === "blocked" || st === "failed" || st === "needs_input";
}

export function reportTaskIdFromFm(
  reportFm: Record<string, unknown>,
  raw?: string,
  filename?: string,
): string {
  const id = raw
    ? resolveReportTaskIdFromContent(reportFm, raw, filename)
    : filename
      ? resolveReportTaskIdFromContent(reportFm, "", filename)
      : resolveReportTaskId(reportFm);
  return id.replace(/\.md$/i, "").trim();
}

export function reportSortKey(filename: string): string {
  const m = filename.match(/^REPORT-(\d{8})-(\d{3})/i);
  if (!m) return filename;
  return `${m[1]}-${m[2]!.padStart(3, "0")}`;
}

export type ParsedReportFile = {
  path: string;
  filename: string;
  raw: string;
  fm: Record<string, unknown>;
  taskId: string;
  sender: string;
  recipient: string;
};

export function parseReportFile(
  path: string,
  filename: string,
  raw: string,
): ParsedReportFile {
  const fm = parseMarkdownFrontmatter(raw);
  return {
    path,
    filename,
    raw,
    fm,
    taskId: reportTaskIdFromFm(fm, raw, filename),
    sender: strField(fm, "sender").toUpperCase(),
    recipient: strField(fm, "recipient").toUpperCase(),
  };
}

/** Pick latest done, non-auto PM→ADMIN report per task_id. */
export function selectCanonicalPmToAdminReports(
  reports: ParsedReportFile[],
): { canonical: ParsedReportFile[]; duplicatePaths: Set<string> } {
  const byTask = new Map<string, ParsedReportFile[]>();
  for (const r of reports) {
    if (!r.taskId) continue;
    const list = byTask.get(r.taskId) ?? [];
    list.push(r);
    byTask.set(r.taskId, list);
  }
  const canonical: ParsedReportFile[] = [];
  const duplicatePaths = new Set<string>();
  for (const list of byTask.values()) {
    const sorted = [...list].sort((a, b) =>
      reportSortKey(b.filename).localeCompare(reportSortKey(a.filename)),
    );
    const doneCandidates = sorted.filter((r) => reportStatusDone(r.fm));
    const scored = doneCandidates.map((r) => {
      const autoRecip = isAutoGeneratedReciprocalReport(r.raw);
      const autoFinal =
        autoRecip ||
        r.fm.auto_final_summary === true ||
        (String(r.fm.report_type ?? "") === "final_summary" &&
          /Runtime\s*总线自动汇总|Runtime\s*总线|close_admin_task\s*草稿生成/i.test(
            r.raw,
          ));
      return { r, manual: autoFinal ? 0 : 1 };
    });
    scored.sort((a, b) => {
      if (b.manual !== a.manual) return b.manual - a.manual;
      return reportSortKey(b.r.filename).localeCompare(
        reportSortKey(a.r.filename),
      );
    });
    if (scored.length > 0) {
      canonical.push(scored[0]!.r);
      for (const { r } of scored.slice(1)) duplicatePaths.add(r.path);
    }
    for (const r of sorted) {
      if (!reportStatusDone(r.fm)) continue;
      if (scored.length > 0 && r !== scored[0]!.r) {
        duplicatePaths.add(r.path);
      }
    }
  }
  return { canonical, duplicatePaths };
}

export function taskStageSkipReason(
  stage: string | undefined,
): SubmitReviewSkipReason | null {
  if (!stage) return "skipped_no_task";
  if (stage === "archive" || stage === "done") return "skipped_archived";
  if (stage === "review") return "skipped_archived";
  if (stage !== "active") return "skipped_not_active";
  return null;
}
