import { createPinia, setActivePinia } from "pinia";
import { beforeEach, expect, test, vi } from "vitest";

const { casesRequest, runsRequest, startRequest, runRequest, eventsRequest, aggregateRequest } = vi.hoisted(() => ({
  casesRequest: vi.fn(),
  runsRequest: vi.fn(),
  startRequest: vi.fn(),
  runRequest: vi.fn(),
  eventsRequest: vi.fn(),
  aggregateRequest: vi.fn()
}));

vi.mock("@/api", () => ({
  caserunAPI: { cases: casesRequest, runs: runsRequest, startRun: startRequest, run: runRequest, events: eventsRequest, aggregate: aggregateRequest }
}));

import { useCaseRunStore } from "./caserun";

beforeEach(() => {
  setActivePinia(createPinia());
  casesRequest.mockReset();
  runsRequest.mockReset();
  startRequest.mockReset();
  runRequest.mockReset();
  eventsRequest.mockReset();
  aggregateRequest.mockReset();
  runsRequest.mockResolvedValue({ ok: true, data: { runs: [], nextCursor: null } });
});

test("run history keeps shared registry summaries and pagination separate from current run", async () => {
  runsRequest
    .mockResolvedValueOnce({ ok: true, data: { runs: [{ runId: "cli-run-2", caseId: "software-smoke", status: "completed", stage: "completed", terminal: true }], nextCursor: "next-page" } })
    .mockResolvedValueOnce({ ok: true, data: { runs: [{ runId: "cli-run-1", caseId: "software-smoke", status: "completed", stage: "completed", terminal: true }], nextCursor: null } });
  const store = useCaseRunStore();

  await store.refreshRuns();
  await store.refreshRuns({ append: true });

  expect(store.runs.map((run) => run.runId)).toEqual(["cli-run-2", "cli-run-1"]);
  expect(store.nextRunsCursor).toBeNull();
  expect(store.currentRun).toBeNull();
  expect(runsRequest).toHaveBeenLastCalledWith({ limit: 30, cursor: "next-page" });
});

test("polling follows API terminal instead of status names", async () => {
  runRequest.mockResolvedValue({ ok: true, data: { runId: "run-1", caseId: "native-completed", status: "custom-progress", stage: "agent-running", terminal: false } });
  eventsRequest.mockResolvedValue({ ok: true, data: { runId: "run-1", events: [] } });
  aggregateRequest.mockResolvedValue({ ok: true, data: { runId: "run-1", status: "custom-progress", sha256: "progress-sha" } });
  const store = useCaseRunStore();

  await store.refreshRun("run-1");
  expect(store.shouldPoll).toBe(true);

  runRequest.mockResolvedValue({ ok: true, data: { runId: "run-1", caseId: "native-completed", status: "running", stage: "completed", terminal: true } });
  await store.refreshRun("run-1");
  expect(store.shouldPoll).toBe(false);
});

test("start keeps blocker and independent aggregate from API read models", async () => {
  startRequest.mockResolvedValue({ ok: true, data: { runId: "run-2", caseId: "native-blocked", status: "queued", stage: "queued", terminal: false } });
  runRequest.mockResolvedValue({ ok: true, data: { runId: "run-2", caseId: "native-blocked", status: "blocked", stage: "preparing", terminal: true, blocker: { code: "native-capability-blocked", summary: "blocked" }, references: { aggregate: { sha256: "embedded-sha" } } } });
  eventsRequest.mockResolvedValue({ ok: true, data: { runId: "run-2", events: [{ status: "blocked", stage: "preparing" }] } });
  aggregateRequest.mockResolvedValue({ ok: true, data: { mode: "native-test", runId: "run-2", status: "blocked", sha256: "api-aggregate-sha" } });
  const store = useCaseRunStore();

  await store.startRun("native-blocked");

  expect(store.currentRun?.blocker?.code).toBe("native-capability-blocked");
  expect(store.aggregate?.runId).toBe("run-2");
  expect(store.aggregate?.status).toBe("blocked");
  expect(store.aggregate?.sha256).toBe("api-aggregate-sha");
  expect(store.shouldPoll).toBe(false);
});
