import { describe, expect, test } from "bun:test";
import { selectRequestDeliveryLineage } from "@overdeck/report-contract";
import type { ObservabilityReportQuery, RequestStoryEvidenceLink, RequestStoryV1 } from "@overdeck/report-contract";
import type { FactoryRunView } from "../adapters/factory";
import type { RequestRow } from "../requests/requests-store";
import { buildExecutionReportSection } from "./execution-report";
import { buildLineageReportSection } from "./lineage-report";

const QUERY: ObservabilityReportQuery = {
  from: "2026-08-16T00:00:00.000Z",
  to: "2026-08-17T00:00:00.000Z",
  timezone: "UTC",
};

function request(overrides: Partial<RequestRow> = {}): RequestRow {
  return {
    id: "request-1", title: "Ship observability reports", project: "overdeck", state: "shipped", priority: "HIGH", origin: "owner",
    asked_at: "2026-08-16T01:00:00.000Z", original_body: "Ship observability reports", original_body_format: "plain_text",
    intake_source: "owner", intake_source_event_id: "request-1", updated_at: "2026-08-16T10:00:00.000Z", worker: "claude", detail: null,
    proof_url: "/legacy-proof", plan_ref: null, factory_run_id: "legacy-run", session_name: null, session_id: null, announced_at: null,
    receipt_trail: [{ id: "legacy-land", request_id: "request-1", at: "2026-08-16T08:00:00.000Z", kind: "landed", line: "Legacy landed", meta: {} }],
    transition_trail: [], ...overrides,
  };
}

function run(): FactoryRunView {
  return {
    adwId: "run-1", repo: "/workspace/overdeck", repoName: "overdeck", adwName: "build", runSlug: "observability-reports",
    preset: null, request: "Ship observability reports", status: "success", engineer: null,
    startedAt: "2026-08-16T02:00:00.000Z", endedAt: "2026-08-16T03:00:00.000Z", totalTokens: 100, totalCost: null,
    phases: [], events: [], attempts: [], gates: [], diffs: [], processes: [], unavailableTables: [], decisions: [],
  };
}

function link(kind: RequestStoryEvidenceLink["kind"], targetId: string, metadata: Record<string, unknown> = {}): RequestStoryEvidenceLink {
  return {
    kind, targetSource: "exact-source", targetId, occurredAt: "2026-08-16T08:00:00.000Z",
    sourceId: "request-evidence", sourceEventId: `${kind}:${targetId}`, ownerUrl: "/reports#lineage", metadata,
  };
}

function story(overrides: Partial<RequestStoryV1> = {}): RequestStoryV1 {
  return {
    schemaVersion: 1, requestId: "request-1", title: "Ship observability reports", project: "overdeck", state: "shipped", priority: "HIGH",
    askedAt: "2026-08-16T01:00:00.000Z", updatedAt: "2026-08-16T10:00:00.000Z",
    originalRequest: { body: "Ship observability reports", format: "plain_text", source: "owner" }, events: [], attachments: [], coverage: [],
    links: [
      link("factory_run", "run-1"), link("gate", "tests", { verdict: "passed" }), link("change", "diff-1"),
      { ...link("branch", "wt/reports", { submittedHead: "a".repeat(40) }), sourceEventId: "land-submitted" },
      { ...link("land_submission", "ticket-1"), sourceEventId: "land-submitted" },
      { ...link("land_submission", "ticket-1"), sourceEventId: "land-result" },
      { ...link("commit", "b".repeat(40), { gateVerdict: "passed" }), sourceEventId: "land-result" },
      link("deployment", "deploy-1", { release: "b".repeat(40), status: "deployed", readiness: "passed" }),
      link("proof", "proof-1", { release: "b".repeat(40), result: "passed" }),
    ],
    ...overrides,
  };
}

function build(requests: RequestRow[] | undefined, stories: RequestStoryV1[] | undefined, factoryRuns: FactoryRunView[] | undefined) {
  const execution = buildExecutionReportSection(QUERY, {
    ...(requests ? { requests } : {}), ...(stories ? { requestStories: stories } : {}), ...(factoryRuns ? { factoryRuns } : {}),
  });
  return buildLineageReportSection({ execution, ...(stories ? { requestStories: stories } : {}) });
}

describe("selectRequestDeliveryLineage", () => {
  test("selects one exact submission, commit, release, and proof chain", () => {
    const selected = selectRequestDeliveryLineage(story().links);
    expect(selected.complete).toBe(true);
    expect(selected.branch?.targetId).toBe("wt/reports");
    expect(selected.submission?.targetId).toBe("ticket-1");
    expect(selected.commit?.targetId).toBe("b".repeat(40));
    expect(selected.deployment?.targetId).toBe("deploy-1");
    expect(selected.proof?.targetId).toBe("proof-1");
  });

  test("does not combine unrelated landing records with the latest commit", () => {
    const links = story().links.map((item) => {
      if (item.kind === "branch") return { ...item, targetId: "wt/unrelated", sourceEventId: "other-submission" };
      if (item.kind === "land_submission" && item.sourceEventId === "land-submitted") {
        return { ...item, targetId: "ticket-other", sourceEventId: "other-submission" };
      }
      return item;
    });
    const selected = selectRequestDeliveryLineage(links);
    expect(selected.complete).toBe(false);
    expect(selected.commit?.targetId).toBe("b".repeat(40));
    expect(selected.branch).toBeUndefined();
  });

  test("keeps a newer deployment-start record partial", () => {
    const started = {
      ...link("deployment", "deploy-2", { release: "b".repeat(40) }),
      occurredAt: "2026-08-16T09:00:00.000Z",
    };
    const selected = selectRequestDeliveryLineage([...story().links, started]);
    expect(selected.complete).toBe(false);
    expect(selected.deployment).toBeUndefined();
  });

  test("rejects deployment and proof records for another release", () => {
    const links = story().links.map((item) =>
      item.kind === "deployment" || item.kind === "proof"
        ? { ...item, metadata: { ...item.metadata, release: "c".repeat(40) } }
        : item);
    const selected = selectRequestDeliveryLineage(links);
    expect(selected.complete).toBe(false);
    expect(selected.commit?.targetId).toBe("b".repeat(40));
  });
});

describe("buildLineageReportSection", () => {
  test("shows a complete lineage only from the same exact links as the request story", () => {
    const section = build([request()], [story()], [run()]);
    expect(section.status).toBe("complete");
    expect(section.lineages[0]).toMatchObject({ complete: true, requestId: "request-1" });
    expect(section.lineages[0]?.stages.map((stage) => [stage.kind, stage.status])).toEqual([
      ["request", "recorded"], ["run", "recorded"], ["gate", "recorded"], ["change", "recorded"],
      ["land", "recorded"], ["deploy", "recorded"], ["proof", "recorded"],
    ]);
  });

  test("does not infer delivery from legacy request fields or matching run prose", () => {
    const section = build([request()], [story({ links: [] })], [run()]);
    expect(section.status).toBe("partial");
    expect(section.lineages[0]?.stages.slice(1).every((stage) => stage.status === "missing")).toBe(true);
  });

  test("requires branch, submission, and commit for the landing stage", () => {
    const incomplete = story({ links: story().links.filter((item) => item.kind !== "land_submission") });
    const section = build([request()], [incomplete], [run()]);
    expect(section.lineages[0]?.stages.find((stage) => stage.kind === "land")).toMatchObject({ status: "missing", label: "Landing incomplete" });
    expect(section.gaps.map((gap) => gap.reason).join(" ")).toContain("landing submission");
  });

  test("keeps unavailable authorities unavailable instead of reporting an empty success", () => {
    const section = build(undefined, undefined, undefined);
    expect(section.status).toBe("unavailable");
    expect(section.lineages).toEqual([]);
    expect(section.gaps.map((gap) => gap.sourceId)).toEqual(expect.arrayContaining(["request-registry", "request-evidence-links"]));
  });

  test("marks an explicitly failed check as failed", () => {
    const failed = story({ links: story().links.map((item) => item.kind === "gate" ? { ...item, metadata: { verdict: "failed" } } : item) });
    const section = build([request()], [failed], [run()]);
    expect(section.status).toBe("complete");
    expect(section.lineages[0]).toMatchObject({ complete: false });
    expect(section.lineages[0]?.stages.find((stage) => stage.kind === "gate")).toMatchObject({ status: "failed", label: "Checks recorded" });
  });
});
