// @vitest-environment jsdom
import { describe, it, expect, vi } from "vitest";
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
import { ProgressBadge } from "./ProgressBadge";
import type { ParsedMessage } from "../lib/types";

// Mock the markdown module to avoid pulling in marked/hljs in jsdom
vi.mock("../lib/markdown", () => ({
  renderMarkdown: (text: string) => `<p>${text}</p>`,
}));

function makeEvent(
  overrides: Partial<ParsedMessage> = {}
): ParsedMessage {
  return {
    uuid: crypto.randomUUID(),
    category: "hook_progress",
    content: "Running pre-commit hook",
    rawIndex: 0,
    timestamp: "2025-01-15T10:30:00Z",
    progressSubtype: "hook",
    ...overrides,
  };
}

describe("ProgressBadge", () => {
  describe("collapsed state", () => {
    it("shows pill counts but hides event content", () => {
      const events = [
        makeEvent({ progressSubtype: "hook" }),
        makeEvent({ progressSubtype: "hook" }),
        makeEvent({ progressSubtype: "bash" }),
      ];
      const { container, queryByText } = render(
        <ProgressBadge events={events} />
      );

      // Pill counts visible
      expect(container.textContent).toContain("hook: 2");
      expect(container.textContent).toContain("bash: 1");

      // Event content should NOT be visible when collapsed
      expect(queryByText("Running pre-commit hook")).toBeNull();
    });
  });

  describe("expanded state", () => {
    it("shows all event content when clicked", () => {
      const events = [
        makeEvent({ content: "First event" }),
        makeEvent({ content: "Second event" }),
      ];
      const { container } = render(<ProgressBadge events={events} />);

      // Click to expand
      fireEvent.click(container.querySelector("button")!);

      // Content should be visible (rendered as markdown via mock)
      expect(container.innerHTML).toContain("First event");
      expect(container.innerHTML).toContain("Second event");
    });

    it("renders content through markdown into prose-message-progress container", () => {
      const events = [
        makeEvent({ content: "**bold text**" }),
      ];
      const { container } = render(<ProgressBadge events={events} />);

      // Expand
      fireEvent.click(container.querySelector("button")!);

      // Our mock wraps in <p>, so the prose container should have rendered HTML
      const proseEl = container.querySelector(".prose-message-progress");
      expect(proseEl).toBeInTheDocument();
      // Content is from local JSONL session files owned by the user,
      // same trust model as MessageBubble's markdown rendering
      expect(proseEl?.innerHTML).toContain("<p>**bold text**</p>");
    });

    it("does not have max-h-48 or overflow-y-auto on expanded container", () => {
      const events = [makeEvent()];
      const { container } = render(<ProgressBadge events={events} />);

      fireEvent.click(container.querySelector("button")!);

      const expandedDiv = container.querySelector("[data-testid='progress-expanded']");
      expect(expandedDiv).toBeInTheDocument();
      expect(expandedDiv?.className).not.toContain("max-h-48");
      expect(expandedDiv?.className).not.toContain("overflow-y-auto");
    });

    it("does not have truncate class on content", () => {
      const events = [makeEvent()];
      const { container } = render(<ProgressBadge events={events} />);

      fireEvent.click(container.querySelector("button")!);

      // Generic (non-agent) expanded view should not truncate
      const proseElements = container.querySelectorAll(".prose-message-progress");
      for (const el of proseElements) {
        expect(el.className).not.toContain("truncate");
      }
    });

    it("displays timestamps and subtype badges per event", () => {
      const events = [
        makeEvent({
          timestamp: "2025-01-15T10:30:00Z",
          progressSubtype: "bash",
          content: "npm test",
        }),
      ];
      const { container } = render(<ProgressBadge events={events} />);

      fireEvent.click(container.querySelector("button")!);

      // Subtype badge visible
      expect(container.textContent).toContain("bash");
      // Timestamp visible (formatted by toLocaleTimeString)
      const expandedDiv = container.querySelector("[data-testid='progress-expanded']");
      expect(expandedDiv).toBeInTheDocument();
      // The timestamp text should exist somewhere in the expanded area
      expect(expandedDiv?.textContent).toMatch(/\d{1,2}:\d{2}:\d{2}/);
    });
  });

  describe("edge cases", () => {
    it("handles empty events array", () => {
      const { container } = render(<ProgressBadge events={[]} />);
      // Should render without crashing, no pills
      expect(container.querySelector("button")).toBeInTheDocument();
    });

    it("handles missing timestamps", () => {
      const events = [makeEvent({ timestamp: undefined })];
      const { container } = render(<ProgressBadge events={events} />);

      fireEvent.click(container.querySelector("button")!);

      expect(container.textContent).toContain("--:--:--");
    });

    it("defaults undefined subtype to hook", () => {
      const events = [makeEvent({ progressSubtype: undefined })];
      const { container } = render(<ProgressBadge events={events} />);

      // In pill counts
      expect(container.textContent).toContain("hook: 1");
    });
  });

  describe("agent subtype delegation", () => {
    function makeAgentEvent(
      overrides: Partial<ParsedMessage> = {}
    ): ParsedMessage {
      const data = {
        message: {
          type: "assistant",
          message: {
            role: "assistant",
            content: [
              {
                type: "tool_use",
                id: "toolu_abc",
                name: "Read",
                input: { file_path: "/src/foo.ts" },
              },
            ],
          },
          timestamp: "2026-01-30T16:22:21.000Z",
        },
        type: "agent_progress",
        prompt: "Explore the codebase",
        agentId: "a6945d4",
      };

      return {
        uuid: crypto.randomUUID(),
        category: "hook_progress",
        content: JSON.stringify(data),
        rawIndex: 0,
        timestamp: "2026-01-30T16:22:21.000Z",
        progressSubtype: "agent",
        ...overrides,
      };
    }

    it("renders AgentProgressView when all events are agent subtype", () => {
      const events = [makeAgentEvent(), makeAgentEvent()];
      const { container } = render(<ProgressBadge events={events} />);

      // Expand
      fireEvent.click(container.querySelector("button")!);

      // Should render AgentProgressView
      expect(
        container.querySelector("[data-testid='agent-progress-view']")
      ).toBeInTheDocument();
      // Should NOT render generic prose-message-progress
      expect(
        container.querySelector(".prose-message-progress")
      ).toBeNull();
    });

    it("renders generic list when events are mixed subtypes", () => {
      const events = [
        makeAgentEvent(),
        makeEvent({ progressSubtype: "hook" }),
      ];
      const { container } = render(<ProgressBadge events={events} />);

      // Expand
      fireEvent.click(container.querySelector("button")!);

      // Should NOT render AgentProgressView
      expect(
        container.querySelector("[data-testid='agent-progress-view']")
      ).toBeNull();
      // Should render generic view
      expect(
        container.querySelector(".prose-message-progress")
      ).toBeInTheDocument();
    });

    it("pills and collapsed state unchanged regardless of subtype", () => {
      const events = [makeAgentEvent(), makeAgentEvent(), makeAgentEvent()];
      const { container } = render(<ProgressBadge events={events} />);

      // Pills show agent count
      expect(container.textContent).toContain("agent: 3");

      // No expanded content initially
      expect(
        container.querySelector("[data-testid='progress-expanded']")
      ).toBeNull();
    });
  });
});
