import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AvailableParticipantsSection } from "~/components/draft/AvailableParticipantsSection";

const defaultProps = {
  participants: [
    { id: "1", name: "Player A", sport: { id: "s1", name: "NFL" } },
    { id: "2", name: "Player B", sport: { id: "s2", name: "NBA" } },
    { id: "3", name: "Player C", sport: { id: "s1", name: "NFL" } },
  ],
  searchQuery: "",
  sportFilters: [] as string[],
  hideDrafted: false,
  hideIneligible: false,
  hideCompletedSports: false,
  uniqueSports: ["NBA", "NFL"],
  userDraftedSportNames: new Set<string>(),
  draftedParticipantIds: new Set<string>(),
  queue: [] as Array<{ id: string; participantId: string }>,
  eligibility: null,
  canPick: false,
  hasTeam: false,
  onSearchChange: vi.fn(),
  onSportFiltersChange: vi.fn(),
  onHideDraftedChange: vi.fn(),
  onHideIneligibleChange: vi.fn(),
  onHideCompletedSportsChange: vi.fn(),
  onMakePick: vi.fn(),
  onAddToQueue: vi.fn(),
  onRemoveFromQueue: vi.fn(),
};

// Both the mobile Sheet trigger and desktop Popover trigger are rendered in jsdom
// (CSS breakpoints are not applied). Click the first one to open the Sheet.
let user: ReturnType<typeof userEvent.setup>;

function clickFirstSportFilterTrigger(name: string | RegExp) {
  return user.click(screen.getAllByRole("button", { name })[0]);
}

describe("AvailableParticipantsSection", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    user = userEvent.setup();
  });

  describe("Rendering", () => {
    it("renders all participants by name", () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      expect(screen.getAllByText("Player A").length).toBeGreaterThan(0);
      expect(screen.getAllByText("Player B").length).toBeGreaterThan(0);
      expect(screen.getAllByText("Player C").length).toBeGreaterThan(0);
    });

    it("renders search input", () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      expect(
        screen.getByPlaceholderText("Search participants...")
      ).toBeInTheDocument();
    });

    it("renders the Show Drafted toggle", () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      expect(screen.getByText("Show Drafted")).toBeInTheDocument();
    });

    it("renders Show Ineligible and Show drafted sports toggles when hasTeam=true", async () => {
      render(
        <AvailableParticipantsSection
          {...defaultProps}
          hasTeam={true}
          eligibility={{ eligibleSportIds: new Set(["s1"]), ineligibleReasons: {} }}
        />
      );
      expect(screen.getByText("Show Ineligible")).toBeInTheDocument();
      // Show drafted sports lives inside the sport filter dropdown
      await clickFirstSportFilterTrigger("Filter by sport: All Sports");
      const dialog = screen.getByRole("dialog");
      expect(within(dialog).getByText("Show drafted sports")).toBeInTheDocument();
    });

    it("does not render Show Ineligible when hasTeam=false", () => {
      render(
        <AvailableParticipantsSection
          {...defaultProps}
          hasTeam={false}
          eligibility={{ eligibleSportIds: new Set(), ineligibleReasons: {} }}
        />
      );
      expect(screen.queryByText("Show Ineligible")).not.toBeInTheDocument();
    });

    it("renders empty state when no participants", () => {
      render(
        <AvailableParticipantsSection {...defaultProps} participants={[]} />
      );
      expect(screen.getAllByText("No participants found.").length).toBeGreaterThan(0);
    });
  });

  describe("Sport Filter - trigger label", () => {
    it('shows "All Sports" in aria-label when no filters selected', () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      // Both mobile and desktop triggers share the same label
      const triggers = screen.getAllByRole("button", {
        name: "Filter by sport: All Sports",
      });
      expect(triggers.length).toBeGreaterThanOrEqual(1);
    });

    it("shows sport name in aria-label when exactly one filter selected", () => {
      render(
        <AvailableParticipantsSection {...defaultProps} sportFilters={["NFL"]} />
      );
      const triggers = screen.getAllByRole("button", {
        name: "Filter by sport: NFL",
      });
      expect(triggers.length).toBeGreaterThanOrEqual(1);
    });

    it("shows count in aria-label when multiple filters selected", () => {
      render(
        <AvailableParticipantsSection
          {...defaultProps}
          sportFilters={["NFL", "NBA"]}
        />
      );
      const triggers = screen.getAllByRole("button", {
        name: "Filter by sport: 2 sports selected",
      });
      expect(triggers.length).toBeGreaterThanOrEqual(1);
    });

    it("does not render active-filter badges", () => {
      render(
        <AvailableParticipantsSection
          {...defaultProps}
          sportFilters={["NFL", "NBA"]}
        />
      );
      expect(screen.queryByLabelText(/Remove .* filter/)).not.toBeInTheDocument();
    });
  });

  describe("Sport Filter - sheet/popover", () => {
    it("opens and shows checkboxes for each sport", async () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      await clickFirstSportFilterTrigger("Filter by sport: All Sports");
      const dialog = screen.getByRole("dialog");
      expect(within(dialog).getByText("NBA")).toBeInTheDocument();
      expect(within(dialog).getByText("NFL")).toBeInTheDocument();
    });

    it("calls onSportFiltersChange with sport added when checkbox clicked", async () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      await clickFirstSportFilterTrigger("Filter by sport: All Sports");
      const dialog = screen.getByRole("dialog");
      await user.click(within(dialog).getByLabelText("NFL"));
      expect(defaultProps.onSportFiltersChange).toHaveBeenCalledWith(["NFL"]);
    });

    it("calls onSportFiltersChange with sport removed when unchecked", async () => {
      render(
        <AvailableParticipantsSection
          {...defaultProps}
          sportFilters={["NFL", "NBA"]}
        />
      );
      await clickFirstSportFilterTrigger("Filter by sport: 2 sports selected");
      const dialog = screen.getByRole("dialog");
      await user.click(within(dialog).getByLabelText("NFL"));
      expect(defaultProps.onSportFiltersChange).toHaveBeenCalledWith(["NBA"]);
    });

    it('does not show "Reset" when no filters active', async () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      await clickFirstSportFilterTrigger("Filter by sport: All Sports");
      const dialog = screen.getByRole("dialog");
      expect(within(dialog).queryByText("Reset")).not.toBeInTheDocument();
    });

    it('shows "Reset" button when filters exist', async () => {
      render(
        <AvailableParticipantsSection {...defaultProps} sportFilters={["NFL"]} />
      );
      await clickFirstSportFilterTrigger("Filter by sport: NFL");
      const dialog = screen.getByRole("dialog");
      expect(within(dialog).getByText("Reset")).toBeInTheDocument();
    });

    it('calls onSportFiltersChange([]) and onHideCompletedSportsChange(false) when "Reset" clicked', async () => {
      render(
        <AvailableParticipantsSection {...defaultProps} sportFilters={["NFL"]} />
      );
      await clickFirstSportFilterTrigger("Filter by sport: NFL");
      const dialog = screen.getByRole("dialog");
      await user.click(within(dialog).getByText("Reset"));
      expect(defaultProps.onSportFiltersChange).toHaveBeenCalledWith([]);
      expect(defaultProps.onHideCompletedSportsChange).toHaveBeenCalledWith(false);
    });

    it("Done button closes the sheet", async () => {
      render(<AvailableParticipantsSection {...defaultProps} />);
      await clickFirstSportFilterTrigger("Filter by sport: All Sports");
      expect(screen.getByRole("dialog")).toBeInTheDocument();
      await user.click(screen.getByRole("button", { name: "Done" }));
      expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
    });
  });
});
