import { readFileSync } from "node:fs";

type JsonRecord = Record<string, unknown>;

function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
  if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}

function source(path: string): string {
  return readFileSync(path, "utf8");
}

function includesAll(text: string, snippets: string[]): boolean {
  return snippets.every((snippet) => text.includes(snippet));
}

export function runDecisionCenterQueryContract(): JsonRecord {
  const service = source("src/components/microservices/decision-center/src/index.ts");
  const cli = source("scripts/src/decision-center.ts");
  const frontend = source("src/components/frontend/src/decision-center.tsx");

  assertCondition(
    includesAll(service, [
      'url.pathname === "/api/requirements" && method === "GET"',
      "listRecords(url, { requirementOnly: true })",
      "type IN ('decision', 'goal', 'external_goal', 'internal_goal', 'blocker', 'debt', 'experiment')",
      "doc_no",
      "doc_type",
      "doc_priority",
      "doc_year",
      "doc_seq",
      "signer",
      "issued_at",
      "effective_scope",
      "supersedes",
      "superseded_by",
    ]),
    "requirements list route must stay on the records model, exclude meetings, and expose document fields",
  );

  assertCondition(
    includesAll(service, [
      "CASE WHEN ${includeBody}::boolean THEN body ELSE left(body, 4000) END AS body",
      "return rows.map((row) => recordFromRow(row, { includeBody }));",
      "body: includeBody ? body : \"\"",
    ]),
    "record list must be body-light by default while preserving summaries",
  );

  assertCondition(
    includesAll(service, [
      "sourceFileFilterFromUrl(url)",
      "url.searchParams.get(\"sourceFile\") ?? url.searchParams.get(\"sourcePath\") ?? url.searchParams.get(\"source\")",
      "AND (${sourceFile || null}::text IS NULL OR source_file = ${sourceFile || null})",
      "getDiaryEntry(key, { sourceFile: sourceFileFilterFromUrl(url) })",
    ]),
    "diary date lookup must support sourceFile disambiguation for same-day entries",
  );
  assertCondition(
    service.split("AND (${sourceFile || null}::text IS NULL OR source_file = ${sourceFile || null})").length >= 3,
    "diary sourceFile filter must cover both read and date-key upsert lookup paths",
  );

  assertCondition(
    includesAll(service, [
      "CASE WHEN ${includeBody}::boolean THEN body ELSE left(body, 4000) END AS body",
      "return rows.map((row) => diaryEntryFromRow(row, { includeBody }));",
    ]),
    "diary list must be body-light by default while preserving summaries",
  );

  assertCondition(
    includesAll(cli, [
      "if (args.includes(\"--include-body\")) params.set(\"includeBody\", \"true\")",
      "function diaryShowQuery(args: string[]): string",
      "params.set(\"sourceFile\", sourceFile)",
      "showDiary(diaryId, args.slice(3))",
      "`/api/requirements${query ? `?${query}` : \"\"}`",
      "parseDocumentNo(optionValue(args, [\"--doc-no\", \"--docNo\", \"--document-no\", \"--documentNo\"])",
      "params.set(\"docNo\", docNo)",
      "payload.docType = docType",
      "payload.signer = signer",
    ]),
    "CLI must expose bounded list opt-in, diary source disambiguation, and document fields",
  );

  assertCondition(
    includesAll(frontend, [
      "function diaryEntryLookupPath(entry: any): string",
      "const key = entry?.id || entry?.date",
      "if (entry?.sourceFile) params.set(\"sourceFile\", String(entry.sourceFile))",
      "decisionApi(apiBaseUrl, diaryEntryLookupPath(entry))",
      "if (!record?.id || record?.body) return",
      "`/api/records/${encodeURIComponent(record.id)}`",
    ]),
    "frontend must select exact diary rows and fetch full record bodies before editing list results",
  );

  return {
    ok: true,
    checks: [
      "requirements-route",
      "body-light-record-list-query",
      "body-light-diary-list-query",
      "diary-source-disambiguation",
      "cli-bounded-list-diary-source-and-document-query",
      "frontend-exact-diary-row-and-record-edit-body",
    ],
  };
}

if (import.meta.main) {
  process.stdout.write(`${JSON.stringify(runDecisionCenterQueryContract(), null, 2)}\n`);
}
