/**
 * Tests for Inbox and InboxView components.
 *
 * TDD: These tests define the expected behavior before implementation.
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Inbox } from "@/components/Inbox";
import { InboxView } from "@/components/InboxView";
import { useInboxStore } from "@/stores/inbox-store";
import { makeInboxItem } from "../helpers/fixtures";
import type { InboxItem, TriageAction, DeferDuration } from "@/lib/types";

const mockNewItems: InboxItem[] = [
  {
    id: "1",
    type: "mention",
    title: "You were mentioned in #312",
    triaged: false,
    createdAt: "2026-02-26T10:00:00Z",
    snippet: "@user can you look at this?",
    actor: "alice",
  },
  {
    id: "2",
    type: "mr_feedback",
    title: "Comment on MR !847",
    triaged: false,
    createdAt: "2026-02-26T09:00:00Z",
    snippet: "This needs some refactoring",
    actor: "bob",
  },
];

describe.skip("Inbox", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("shows only untriaged items", () => {
    const items: InboxItem[] = [
      ...mockNewItems,
      {
        id: "3",
        type: "mention",
        title: "Already triaged",
        triaged: true,
        createdAt: "2026-02-26T08:00:00Z",
      },
    ];
    render(<Inbox items={items} onTriage={vi.fn()} />);

    const inboxItems = screen.getAllByTestId("inbox-item");
    expect(inboxItems).toHaveLength(2);
  });

  it("shows inbox zero state when empty", () => {
    render(<Inbox items={[]} onTriage={vi.fn()} />);

    expect(screen.getByText(/Inbox Zero/i)).toBeInTheDocument();
    expect(screen.getByText(/All caught up/i)).toBeInTheDocument();
  });

  it("shows inbox zero when all items are triaged", () => {
    const items: InboxItem[] = [
      {
        id: "1",
        type: "mention",
        title: "Triaged item",
        triaged: true,
        createdAt: "2026-02-26T10:00:00Z",
      },
    ];
    render(<Inbox items={items} onTriage={vi.fn()} />);

    expect(screen.getByText(/Inbox Zero/i)).toBeInTheDocument();
  });

  it("accept moves item to queue", async () => {
    const user = userEvent.setup();
    const onTriage = vi.fn();
    render(<Inbox items={mockNewItems} onTriage={onTriage} />);

    const acceptButtons = screen.getAllByRole("button", { name: /accept/i });
    await user.click(acceptButtons[0]);

    expect(onTriage).toHaveBeenCalledWith("1", "accept", undefined);
  });

  it("defer shows duration picker", async () => {
    const user = userEvent.setup();
    render(<Inbox items={mockNewItems} onTriage={vi.fn()} />);

    const deferButtons = screen.getAllByRole("button", { name: /defer/i });
    await user.click(deferButtons[0]);

    // Defer picker should show duration options
    expect(screen.getByText("1 hour")).toBeInTheDocument();
    expect(screen.getByText("Tomorrow")).toBeInTheDocument();
  });

  it("defer with duration calls onTriage", async () => {
    const user = userEvent.setup();
    const onTriage = vi.fn();
    render(<Inbox items={mockNewItems} onTriage={onTriage} />);

    const deferButtons = screen.getAllByRole("button", { name: /defer/i });
    await user.click(deferButtons[0]);
    await user.click(screen.getByText("1 hour"));

    expect(onTriage).toHaveBeenCalledWith("1", "defer", "1h");
  });

  it("archive removes item from view", async () => {
    const user = userEvent.setup();
    const onTriage = vi.fn();
    render(<Inbox items={mockNewItems} onTriage={onTriage} />);

    const archiveButtons = screen.getAllByRole("button", { name: /archive/i });
    await user.click(archiveButtons[0]);

    expect(onTriage).toHaveBeenCalledWith("1", "archive", undefined);
  });

  it("displays item metadata", () => {
    render(<Inbox items={mockNewItems} onTriage={vi.fn()} />);

    expect(screen.getByText("You were mentioned in #312")).toBeInTheDocument();
    expect(screen.getByText("@user can you look at this?")).toBeInTheDocument();
    expect(screen.getByText("alice")).toBeInTheDocument();
  });

  it("displays item count in header", () => {
    render(<Inbox items={mockNewItems} onTriage={vi.fn()} />);

    expect(screen.getByText(/Inbox \(2\)/)).toBeInTheDocument();
  });

  describe("keyboard shortcuts", () => {
    it("pressing 'a' on focused item triggers accept", async () => {
      const user = userEvent.setup();
      const onTriage = vi.fn();
      render(<Inbox items={mockNewItems} onTriage={onTriage} />);

      // Focus the first inbox item
      const firstItem = screen.getAllByTestId("inbox-item")[0];
      firstItem.focus();

      await user.keyboard("a");

      expect(onTriage).toHaveBeenCalledWith("1", "accept", undefined);
    });

    it("pressing 'd' on focused item opens defer picker", async () => {
      const user = userEvent.setup();
      render(<Inbox items={mockNewItems} onTriage={vi.fn()} />);

      // Focus the first inbox item
      const firstItem = screen.getAllByTestId("inbox-item")[0];
      firstItem.focus();

      await user.keyboard("d");

      expect(screen.getByText("1 hour")).toBeInTheDocument();
    });

    it("pressing 'x' on focused item triggers archive", async () => {
      const user = userEvent.setup();
      const onTriage = vi.fn();
      render(<Inbox items={mockNewItems} onTriage={onTriage} />);

      // Focus the first inbox item
      const firstItem = screen.getAllByTestId("inbox-item")[0];
      firstItem.focus();

      await user.keyboard("x");

      expect(onTriage).toHaveBeenCalledWith("1", "archive", undefined);
    });
  });
});

/**
 * InboxView container tests - integrates with inbox store
 */
describe("InboxView", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Reset inbox store to initial state
    useInboxStore.setState({
      items: [],
      isLoading: false,
      error: null,
    });
  });

  it("shows only untriaged items from store", () => {
    useInboxStore.setState({
      items: [
        makeInboxItem({ id: "1", triaged: false, title: "Mention in #312" }),
        makeInboxItem({ id: "2", triaged: false, title: "Comment on MR !847" }),
        makeInboxItem({ id: "3", triaged: true, title: "Already done" }),
      ],
    });

    render(<InboxView />);

    const inboxItems = screen.getAllByTestId("inbox-item");
    expect(inboxItems).toHaveLength(2);
    expect(screen.queryByText("Already done")).not.toBeInTheDocument();
  });

  it("shows inbox zero celebration when empty", () => {
    useInboxStore.setState({ items: [] });

    render(<InboxView />);

    expect(screen.getByText(/Inbox Zero/i)).toBeInTheDocument();
    expect(screen.getByText(/All caught up/i)).toBeInTheDocument();
  });

  it("shows inbox zero when all items are triaged", () => {
    useInboxStore.setState({
      items: [
        makeInboxItem({ id: "1", triaged: true, title: "Triaged item" }),
      ],
    });

    render(<InboxView />);

    expect(screen.getByText(/Inbox Zero/i)).toBeInTheDocument();
  });

  it("accept triage action updates item in store", async () => {
    const user = userEvent.setup();
    useInboxStore.setState({
      items: [
        makeInboxItem({ id: "1", triaged: false, title: "Mention in #312" }),
      ],
    });

    render(<InboxView />);

    const acceptButton = screen.getByRole("button", { name: /accept/i });
    await user.click(acceptButton);

    // Item should be marked as triaged
    const { items } = useInboxStore.getState();
    expect(items[0].triaged).toBe(true);
  });

  it("archive triage action updates item in store", async () => {
    const user = userEvent.setup();
    useInboxStore.setState({
      items: [
        makeInboxItem({ id: "1", triaged: false, title: "Mention in #312" }),
      ],
    });

    render(<InboxView />);

    const archiveButton = screen.getByRole("button", { name: /archive/i });
    await user.click(archiveButton);

    // Item should be marked as triaged and archived
    const { items } = useInboxStore.getState();
    expect(items[0].triaged).toBe(true);
    expect(items[0].archived).toBe(true);
  });

  it("updates count in real-time after triage", async () => {
    const user = userEvent.setup();
    useInboxStore.setState({
      items: [
        makeInboxItem({ id: "1", triaged: false, title: "Item 1" }),
        makeInboxItem({ id: "2", triaged: false, title: "Item 2" }),
      ],
    });

    render(<InboxView />);

    expect(screen.getByText(/Inbox \(2\)/)).toBeInTheDocument();

    const acceptButtons = screen.getAllByRole("button", { name: /accept/i });
    await user.click(acceptButtons[0]);

    expect(screen.getByText(/Inbox \(1\)/)).toBeInTheDocument();
  });

  it("displays keyboard shortcut hints", () => {
    useInboxStore.setState({
      items: [makeInboxItem({ id: "1", triaged: false })],
    });

    render(<InboxView />);

    // Check for keyboard hints text (using more specific selectors to avoid button text)
    expect(screen.getByText("j/k")).toBeInTheDocument();
    expect(screen.getByText(/navigate/i)).toBeInTheDocument();
    // The hint text contains lowercase "a" in a kbd element
    expect(screen.getAllByText(/accept/i).length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText(/defer/i).length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText(/archive/i).length).toBeGreaterThanOrEqual(1);
  });

  describe("keyboard navigation", () => {
    it("arrow down moves focus to next item", async () => {
      const user = userEvent.setup();
      useInboxStore.setState({
        items: [
          makeInboxItem({ id: "1", triaged: false, title: "Item 1" }),
          makeInboxItem({ id: "2", triaged: false, title: "Item 2" }),
        ],
      });

      render(<InboxView />);

      // Focus container and press down arrow
      const container = screen.getByTestId("inbox-view");
      container.focus();
      await user.keyboard("{ArrowDown}");

      // Second item should be highlighted (focused index = 1)
      const items = screen.getAllByTestId("inbox-item");
      expect(items[1]).toHaveAttribute("data-focused", "true");
    });

    it("arrow up moves focus to previous item", async () => {
      const user = userEvent.setup();
      useInboxStore.setState({
        items: [
          makeInboxItem({ id: "1", triaged: false, title: "Item 1" }),
          makeInboxItem({ id: "2", triaged: false, title: "Item 2" }),
        ],
      });

      render(<InboxView />);

      const container = screen.getByTestId("inbox-view");
      container.focus();
      // Move down then up
      await user.keyboard("{ArrowDown}");
      await user.keyboard("{ArrowUp}");

      const items = screen.getAllByTestId("inbox-item");
      expect(items[0]).toHaveAttribute("data-focused", "true");
    });

    it("pressing 'a' on focused item triggers accept", async () => {
      const user = userEvent.setup();
      useInboxStore.setState({
        items: [makeInboxItem({ id: "1", triaged: false, title: "Item 1" })],
      });

      render(<InboxView />);

      const container = screen.getByTestId("inbox-view");
      container.focus();
      await user.keyboard("a");

      const { items } = useInboxStore.getState();
      expect(items[0].triaged).toBe(true);
    });

    it("pressing 'x' on focused item triggers archive", async () => {
      const user = userEvent.setup();
      useInboxStore.setState({
        items: [makeInboxItem({ id: "1", triaged: false, title: "Item 1" })],
      });

      render(<InboxView />);

      const container = screen.getByTestId("inbox-view");
      container.focus();
      await user.keyboard("x");

      const { items } = useInboxStore.getState();
      expect(items[0].triaged).toBe(true);
      expect(items[0].archived).toBe(true);
    });
  });
});
