import { fireEvent, render, screen } from "@testing-library/react";
import { AccordionList } from "./AccordionList";
import { mockMatchMedia } from "../../utils/mockMatchMedia";

const ACCORDION_LIST_CLASS_NAME = "mobius-accordion-list";

describe("AccordionList", () => {
  beforeEach(() => {
    mockMatchMedia(true);
  });

  const mockContent = [
    { id: "section-1", header: "Section 1", details: "Details for section 1" },
    { id: "section-2", header: "Section 2", details: "Details for section 2" },
    { id: "section-3", header: "Section 3", details: "Details for section 3" },
  ];

  it("should render without errors", () => {
    const view = render(<AccordionList content={mockContent} />);
    expect(view).toBeTruthy();
  });

  it("should render the correct number of accordions", () => {
    render(<AccordionList content={mockContent} />);
    expect(screen.getByText("Section 1")).toBeInTheDocument();
    expect(screen.getByText("Section 2")).toBeInTheDocument();
    expect(screen.getByText("Section 3")).toBeInTheDocument();
  });

  it("should render dividers between accordions", () => {
    render(<AccordionList content={mockContent} />);
    const dividers = screen.getAllByRole("separator");
    // Should have n-1 dividers for n items
    expect(dividers).toHaveLength(2);
  });

  it("should apply the accordion list class name", () => {
    const { container } = render(<AccordionList content={mockContent} />);
    expect(container.firstChild).toHaveClass(ACCORDION_LIST_CLASS_NAME);
  });

  it("should apply custom className", () => {
    const customClass = "custom-class";
    const { container } = render(
      <AccordionList content={mockContent} className={customClass} />,
    );
    expect(container.firstChild).toHaveClass(
      ACCORDION_LIST_CLASS_NAME,
      customClass,
    );
  });

  it("should support exclusive expansion (only one open at a time)", () => {
    render(<AccordionList content={mockContent} />);

    const buttons = screen.getAllByRole("button");
    const section1Toggle = buttons[0];
    const section2Toggle = buttons[1];

    // Initially, both should be closed (aria-expanded false)
    expect(section1Toggle).toHaveAttribute("aria-expanded", "false");
    expect(section2Toggle).toHaveAttribute("aria-expanded", "false");

    // Open first accordion
    fireEvent.click(section1Toggle);
    expect(section1Toggle).toHaveAttribute("aria-expanded", "true");
    expect(section2Toggle).toHaveAttribute("aria-expanded", "false");

    // Open second accordion (should close first)
    fireEvent.click(section2Toggle);
    expect(section1Toggle).toHaveAttribute("aria-expanded", "false");
    expect(section2Toggle).toHaveAttribute("aria-expanded", "true");
  });

  it("should call onOpen callback with correct id", () => {
    const onOpen = vi.fn();
    render(<AccordionList content={mockContent} onOpen={onOpen} />);

    const section2Toggle = screen.getByText("Section 2");
    fireEvent.click(section2Toggle);

    expect(onOpen).toHaveBeenCalledWith("section-2");
  });

  it("should call onClose callback with correct id", () => {
    const onClose = vi.fn();
    render(<AccordionList content={mockContent} onClose={onClose} />);

    const section1Toggle = screen.getByText("Section 1");

    // Open accordion
    fireEvent.click(section1Toggle);

    // Close accordion
    fireEvent.click(section1Toggle);

    expect(onClose).toHaveBeenCalledWith("section-1");
  });

  it("should render header as ReactNode when provided", () => {
    const content = [
      {
        id: "custom-header-item",
        header: <span data-testid="custom-header">Custom Header</span>,
        details: "Details",
      },
    ];
    render(<AccordionList content={content} />);

    expect(screen.getByTestId("custom-header")).toBeInTheDocument();
  });

  it("should render details as ReactNode when provided", () => {
    const content = [
      {
        id: "custom-details-item",
        header: "Header",
        details: <span data-testid="custom-details">Custom Details</span>,
      },
    ];
    render(<AccordionList content={content} />);

    const headerToggle = screen.getByText("Header");
    fireEvent.click(headerToggle);

    expect(screen.getByTestId("custom-details")).toBeInTheDocument();
  });

  it("should pass through DOM props", () => {
    const { container } = render(
      <AccordionList content={mockContent} data-testid="test-list" />,
    );

    expect(container.firstChild).toHaveAttribute("data-testid", "test-list");
  });

  describe("allowMultiple prop", () => {
    it("should allow multiple accordions to be open when allowMultiple is true", () => {
      render(<AccordionList content={mockContent} allowMultiple={true} />);

      const buttons = screen.getAllByRole("button");
      const section1Toggle = buttons[0];
      const section2Toggle = buttons[1];
      const section3Toggle = buttons[2];

      // Initially, all should be closed
      expect(section1Toggle).toHaveAttribute("aria-expanded", "false");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "false");
      expect(section3Toggle).toHaveAttribute("aria-expanded", "false");

      // Open first accordion
      fireEvent.click(section1Toggle);
      expect(section1Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "false");
      expect(section3Toggle).toHaveAttribute("aria-expanded", "false");

      // Open second accordion (first should remain open)
      fireEvent.click(section2Toggle);
      expect(section1Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section3Toggle).toHaveAttribute("aria-expanded", "false");

      // Open third accordion (both first and second should remain open)
      fireEvent.click(section3Toggle);
      expect(section1Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section3Toggle).toHaveAttribute("aria-expanded", "true");
    });

    it("should allow closing individual accordions when allowMultiple is true", () => {
      render(<AccordionList content={mockContent} allowMultiple={true} />);

      const buttons = screen.getAllByRole("button");
      const section1Toggle = buttons[0];
      const section2Toggle = buttons[1];

      // Open both accordions
      fireEvent.click(section1Toggle);
      fireEvent.click(section2Toggle);
      expect(section1Toggle).toHaveAttribute("aria-expanded", "true");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "true");

      // Close first accordion (second should remain open)
      fireEvent.click(section1Toggle);
      expect(section1Toggle).toHaveAttribute("aria-expanded", "false");
      expect(section2Toggle).toHaveAttribute("aria-expanded", "true");
    });

    it("should call onOpen and onClose callbacks correctly when allowMultiple is true", () => {
      const onOpen = vi.fn();
      const onClose = vi.fn();
      render(
        <AccordionList
          content={mockContent}
          allowMultiple={true}
          onOpen={onOpen}
          onClose={onClose}
        />,
      );

      const buttons = screen.getAllByRole("button");

      // Open first accordion
      fireEvent.click(buttons[0]);
      expect(onOpen).toHaveBeenCalledWith("section-1");

      // Open second accordion
      fireEvent.click(buttons[1]);
      expect(onOpen).toHaveBeenCalledWith("section-2");

      // Close first accordion
      fireEvent.click(buttons[0]);
      expect(onClose).toHaveBeenCalledWith("section-1");

      expect(onOpen).toHaveBeenCalledTimes(2);
      expect(onClose).toHaveBeenCalledTimes(1);
    });
  });
});
