/** Tests for GatewayPanel — verifies story id and name rendering in the gateway aggregate view. */
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import type { PipelineItem } from "../api/gateway";
import { StoryRow } from "./GatewayPanel";

describe("StoryRow", () => {
	it("renders #id prefix before the story name", () => {
		const item: PipelineItem = {
			story_id: "42_story_add_feature",
			name: "Add Feature",
			stage: "current",
		};
		const { container } = render(<StoryRow item={item} />);
		expect(container).toMatchSnapshot();
	});

	it("renders #id prefix for a backlogged story", () => {
		const item: PipelineItem = {
			story_id: "7_bug_fix_crash",
			name: "Fix crash on startup",
			stage: "qa",
		};
		const { container } = render(<StoryRow item={item} />);
		expect(container).toMatchSnapshot();
	});

	it("renders awaiting-slot badge for merge item with no agent", () => {
		const item: PipelineItem = {
			story_id: "no-number-id",
			name: "Mystery Story",
			stage: "merge",
		};
		const { container } = render(<StoryRow item={item} />);
		expect(container).toMatchSnapshot();
		expect(screen.getByText("awaiting-slot")).toBeInTheDocument();
	});

	// AC1: active mergemaster is visually distinct
	it("shows MERGING badge for merge item with running mergemaster (active)", () => {
		const item: PipelineItem = {
			story_id: "70_story_merging_active",
			name: "Merging Active",
			stage: "merge",
			agent: { agent_name: "mergemaster", model: "claude", status: "running" },
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("▶ MERGING")).toBeInTheDocument();
	});

	// AC2: awaiting-slot with queue position labels
	it("shows NEXT IN QUEUE for first awaiting-slot merge item", () => {
		const item: PipelineItem = {
			story_id: "71_story_next_in_queue",
			name: "Next in Queue",
			stage: "merge",
		};
		render(<StoryRow item={item} mergeQueuePos={1} />);
		expect(screen.getByText("NEXT IN QUEUE")).toBeInTheDocument();
	});

	it("shows awaiting-slot with position for subsequent queued merge items", () => {
		const item: PipelineItem = {
			story_id: "72_story_second_in_queue",
			name: "Second in Queue",
			stage: "merge",
		};
		render(<StoryRow item={item} mergeQueuePos={2} />);
		expect(screen.getByText("awaiting-slot (#2)")).toBeInTheDocument();
	});

	// Story 1085: failure kind no longer derived from substring.  Items in
	// the merge_failure / merge_failure_final status get a generic FAILED badge;
	// the kind detail is exposed via the typed `status` field for callers that
	// need it (instead of being squeezed into the badge text).
	it("shows ✕ FAILED badge for merge-failure status", () => {
		const item: PipelineItem = {
			story_id: "73_story_conflict",
			name: "Conflict Story",
			stage: "merge",
			pipeline: "merge",
			status: "merge-failure",
			merge_failure: "Merge conflict: conflicts detected",
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("✕ FAILED")).toBeInTheDocument();
	});

	it("shows ⛔ FAILED (FINAL) badge for merge-failure-final status", () => {
		const item: PipelineItem = {
			story_id: "74_story_gates",
			name: "Gates Failed Story",
			stage: "merge",
			pipeline: "merge",
			status: "merge-failure-final",
			merge_failure: "Quality gates failed: cargo test failed",
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⛔ FAILED (FINAL)")).toBeInTheDocument();
	});

	it("shows RECOVERING badge for merge_failure item with running mergemaster", () => {
		const item: PipelineItem = {
			story_id: "60_story_merge_recovering",
			name: "Merge Recovering",
			stage: "merge",
			merge_failure: "Squash merge failed",
			agent: { agent_name: "mergemaster", model: "claude", status: "running" },
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⟳ RECOVERING")).toBeInTheDocument();
	});

	it("shows QUEUED badge for merge_failure item with pending mergemaster", () => {
		const item: PipelineItem = {
			story_id: "61_story_merge_queued",
			name: "Merge Queued",
			stage: "merge",
			merge_failure: "Squash merge failed",
			agent: { agent_name: "mergemaster", model: "claude", status: "pending" },
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⏳ QUEUED")).toBeInTheDocument();
	});

	it("shows FAILED badge for merge_failure item with no recovery agent", () => {
		const item: PipelineItem = {
			story_id: "62_story_merge_final",
			name: "Merge Final",
			stage: "merge",
			merge_failure: "Squash merge failed",
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("✕ FAILED")).toBeInTheDocument();
	});

	it("shows RECOVERING badge for blocked item with running recovery agent", () => {
		const item: PipelineItem = {
			story_id: "63_story_blocked_recovering",
			name: "Blocked Recovering",
			stage: "current",
			blocked: true,
			agent: { agent_name: "coder", model: "claude", status: "running" },
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⟳ RECOVERING")).toBeInTheDocument();
	});

	it("shows QUEUED badge for blocked item with pending recovery agent", () => {
		const item: PipelineItem = {
			story_id: "64_story_blocked_queued",
			name: "Blocked Queued",
			stage: "current",
			blocked: true,
			agent: { agent_name: "coder", model: "claude", status: "pending" },
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⏳ QUEUED")).toBeInTheDocument();
	});

	it("shows BLOCKED badge for blocked item with no recovery agent", () => {
		const item: PipelineItem = {
			story_id: "65_story_blocked_human",
			name: "Blocked Human",
			stage: "current",
			blocked: true,
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("⊘ BLOCKED")).toBeInTheDocument();
	});

	// Story 1085 AC 4 — Frozen items remain visible in their underlying column
	// with a frozen indicator. The server hands us `pipeline: "coding"` for a
	// frozen-while-coding story and the badge is decorated separately.
	it("shows ❄ FROZEN badge for a frozen item (column stays as underlying pipeline)", () => {
		const item: PipelineItem = {
			story_id: "70_story_frozen_coding",
			name: "Paused Coding Story",
			stage: "current",
			pipeline: "coding",
			status: "frozen",
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("❄ FROZEN")).toBeInTheDocument();
	});

	// Story 1085 AC 4 (subsumes 1052) — Done items must never get a
	// MergeFailure indicator, even if a stale `merge_failure` string is present.
	it("done items render Done badge, never MergeFailure", () => {
		const item: PipelineItem = {
			story_id: "71_story_done",
			name: "Completed Story",
			stage: "done",
			pipeline: "done",
			status: "done",
			merge_failure: "ignored stale string",
		};
		render(<StoryRow item={item} />);
		expect(screen.getByText("Done")).toBeInTheDocument();
		expect(screen.queryByText("✕ FAILED")).not.toBeInTheDocument();
		expect(screen.queryByText(/FAILED/)).not.toBeInTheDocument();
	});
});
