/**
 * GET /api/jobs/[id] — public read of an investigation_jobs row.
 *
 * Hydrates the outputs[] payload by joining to public.evidence / public.hypotheses
 * so the /jobs/[id] page can render evidence cards + hypothesis cards without
 * n+1 round-trips.
 *
 * No auth required (read-only): anyone with a job_id can see status. This
 * matches the chat tool's UX: the chat reveals the URL, the user opens it,
 * the page renders. No PII is exposed beyond what the user already typed
 * (triggered_by carries their email — we strip it).
 */
import { NextResponse } from "next/server";
import { pgQuery } from "@/lib/retrieval/db";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

interface JobRow {
  job_id: string;
  kind: string;
  payload: Record<string, unknown> | null;
  status: string;
  worker_id: string | null;
  started_at: string | null;
  finished_at: string | null;
  outputs: unknown;
  error: string | null;
  created_at: string;
}

interface EvidenceRow {
  evidence_id: string;
  grade: string | null;
  source_page_id: string;
  doc_id: string | null;
  page: number | null;
  chunk_id: string | null;
  verbatim_excerpt: string | null;
  custody_steps: unknown;
  bbox: unknown;
  confidence_band: string | null;
  related_hypotheses: unknown;
}

interface HypothesisRow {
  hypothesis_id: string;
  question: string | null;
  question_pt_br: string | null;
  position: string | null;
  position_pt_br: string | null;
  argument_for: string | null;
  argument_for_pt_br: string | null;
  argument_against: string | null;
  argument_against_pt_br: string | null;
  prior: number | null;
  posterior: number | null;
  confidence_band: string | null;
  status: string | null;
  evidence_refs: unknown;
}

interface ContradictionRow {
  contradiction_id: string;
  topic: string;
  topic_pt_br: string | null;
  chunks: unknown;
  resolution_status: string | null;
  notes: string | null;
  notes_pt_br: string | null;
  detected_by: string | null;
}

interface WitnessRow {
  witness_id: string;
  canonical_name: string | null;
  entity_id: string | null;
  credibility: string | null;
  access_to_event: string | null;
  access_to_event_pt_br: string | null;
  bias_notes: string | null;
  bias_notes_pt_br: string | null;
  corroboration_refs: unknown;
  verdict: string | null;
  verdict_pt_br: string | null;
}

interface GapRow {
  gap_id: string;
  description: string;
  description_pt_br: string | null;
  scope: unknown;
  suggested_next_move: string | null;
  suggested_next_move_pt_br: string | null;
  status: string;
  created_by: string;
}

function durationMs(started: string | null, finished: string | null, created: string): number | null {
  const a = started ? new Date(started).getTime() : null;
  const b = finished ? new Date(finished).getTime() : null;
  if (a !== null && b !== null) return b - a;
  if (a !== null) return Date.now() - a;
  return Date.now() - new Date(created).getTime();
}

export async function GET(
  _request: Request,
  ctx: { params: Promise<{ id: string }> },
) {
  const { id } = await ctx.params;
  if (!/^[0-9a-f-]{36}$/i.test(id)) {
    return NextResponse.json({ error: "bad_job_id" }, { status: 400 });
  }
  try {
    const rows = await pgQuery<JobRow>(
      `SELECT job_id, kind, payload, status, worker_id, started_at, finished_at,
              outputs, error, created_at
         FROM public.investigation_jobs WHERE job_id = $1`,
      [id],
    );
    const job = rows[0];
    if (!job) return NextResponse.json({ error: "not_found" }, { status: 404 });

    // Collect IDs surfaced in outputs[] for hydration.
    const evidenceIds: string[] = [];
    const hypothesisIds: string[] = [];
    const contradictionIds: string[] = [];
    const witnessIds: string[] = [];
    const gapIds: string[] = [];
    if (Array.isArray(job.outputs)) {
      for (const o of job.outputs as Array<Record<string, unknown>>) {
        if (typeof o.evidence_id === "string") evidenceIds.push(o.evidence_id);
        if (typeof o.hypothesis_id === "string") hypothesisIds.push(o.hypothesis_id);
        if (typeof o.contradiction_id === "string") contradictionIds.push(o.contradiction_id);
        if (typeof o.witness_id === "string") witnessIds.push(o.witness_id);
        if (typeof o.gap_id === "string") gapIds.push(o.gap_id);
      }
    }

    const [evidence, hypotheses, contradictions, witnesses, gaps] = await Promise.all([
      evidenceIds.length > 0
        ? pgQuery<EvidenceRow>(
            `SELECT e.evidence_id, e.grade, e.source_page_id,
                    split_part(e.source_page_id, '/p', 1)                  AS doc_id,
                    NULLIF(split_part(e.source_page_id, '/p', 2), '')::int AS page,
                    c.chunk_id, e.verbatim_excerpt, e.custody_steps, e.bbox,
                    e.confidence_band, e.related_hypotheses
               FROM public.evidence e
          LEFT JOIN public.chunks c ON c.chunk_pk = e.source_chunk_pk
              WHERE e.evidence_id = ANY($1::text[])
              ORDER BY e.evidence_id`,
            [evidenceIds],
          )
        : Promise.resolve([] as EvidenceRow[]),
      hypothesisIds.length > 0
        ? pgQuery<HypothesisRow>(
            `SELECT hypothesis_id, question, question_pt_br, position, position_pt_br,
                    argument_for, argument_for_pt_br, argument_against, argument_against_pt_br,
                    prior, posterior, confidence_band, status, evidence_refs
               FROM public.hypotheses
              WHERE hypothesis_id = ANY($1::text[])
              ORDER BY hypothesis_id`,
            [hypothesisIds],
          )
        : Promise.resolve([] as HypothesisRow[]),
      contradictionIds.length > 0
        ? pgQuery<ContradictionRow>(
            `SELECT contradiction_id, topic, topic_pt_br, chunks, resolution_status,
                    notes, notes_pt_br, detected_by
               FROM public.contradictions
              WHERE contradiction_id = ANY($1::text[])
              ORDER BY contradiction_id`,
            [contradictionIds],
          )
        : Promise.resolve([] as ContradictionRow[]),
      witnessIds.length > 0
        ? pgQuery<WitnessRow>(
            `SELECT w.witness_id, e.canonical_name, e.entity_id, w.credibility,
                    w.access_to_event, w.access_to_event_pt_br,
                    w.bias_notes, w.bias_notes_pt_br,
                    w.corroboration_refs, w.verdict, w.verdict_pt_br
               FROM public.witnesses w
          LEFT JOIN public.entities e ON e.entity_pk = w.person_entity_pk
              WHERE w.witness_id = ANY($1::text[])
              ORDER BY w.witness_id`,
            [witnessIds],
          )
        : Promise.resolve([] as WitnessRow[]),
      gapIds.length > 0
        ? pgQuery<GapRow>(
            `SELECT gap_id, description, description_pt_br, scope,
                    suggested_next_move, suggested_next_move_pt_br, status, created_by
               FROM public.gaps WHERE gap_id = ANY($1::text[]) ORDER BY gap_id`,
            [gapIds],
          )
        : Promise.resolve([] as GapRow[]),
    ]);

    return NextResponse.json({
      job_id: job.job_id,
      kind: job.kind,
      payload: job.payload,
      status: job.status,
      worker_id: job.worker_id,
      started_at: job.started_at,
      finished_at: job.finished_at,
      created_at: job.created_at,
      duration_ms: durationMs(job.started_at, job.finished_at, job.created_at),
      error: job.error,
      outputs: Array.isArray(job.outputs) ? job.outputs : [],
      evidence,
      hypotheses,
      contradictions,
      witnesses,
      gaps,
    });
  } catch (e) {
    return NextResponse.json({ error: "db_unavailable", message: (e as Error).message }, { status: 503 });
  }
}
