import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { BrowserRouter } from "react-router";
import { TeamScoreBreakdown } from "../TeamScoreBreakdown";

function renderWithRouter(ui: React.ReactElement) {
  return render(<BrowserRouter>{ui}</BrowserRouter>);
}

describe("TeamScoreBreakdown", () => {
  const mockLeagueId = "league-123";
  const mockSeasonId = "season-456";
  // 2-team league: pick 1 = 1.01, pick 2 = 1.02, pick 3 = 2.01
  const numTeams = 2;

  const mockBreakdown = {
    team: {
      id: "team-1",
      name: "Test Team",
    },
    picks: [
      {
        pickNumber: 1,
        round: 1,
        participant: {
          id: "p1",
          name: "Team A",
          sport: "NFL",
          sportsSeasonId: "ss-nfl",
        },
        finalPosition: 1,
        points: 100,
        projectedPoints: null,
        isComplete: true,
        isPartialScore: false,
      },
      {
        pickNumber: 2,
        round: 1,
        participant: {
          id: "p2",
          name: "Driver B",
          sport: "F1",
          sportsSeasonId: "ss-f1",
        },
        finalPosition: 3,
        points: 50,
        projectedPoints: null,
        isComplete: true,
        isPartialScore: false,
      },
      {
        pickNumber: 3,
        round: 2,
        participant: {
          id: "p3",
          name: "Team C",
          sport: "NFL",
          sportsSeasonId: "ss-nfl",
        },
        finalPosition: null,
        points: 0,
        projectedPoints: 25,
        isComplete: false,
        isPartialScore: false,
      },
    ],
    actualPoints: 150,
    projectedPoints: 175,
    completedCount: 2,
    totalCount: 3,
  };

  const mockStanding = { currentRank: 1 };

  describe("Basic Rendering", () => {
    it("should render team name and actual points", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Test Team")).toBeInTheDocument();
      expect(screen.getAllByText("150.00").length).toBeGreaterThanOrEqual(1);
    });

    it("should show projected points when higher than actual", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("175.00")).toBeInTheDocument();
      expect(screen.getByText("projected")).toBeInTheDocument();
    });

    it("should show remaining participant count", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("1 participant remaining")).toBeInTheDocument();
    });

    it("should show team rank badge", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Rank #1")).toBeInTheDocument();
    });

    it("should handle null team", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={{ ...mockBreakdown, team: null }}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Team not found")).toBeInTheDocument();
    });
  });

  describe("Pick Number Display", () => {
    it("should format picks as round.pick notation", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("1.01")).toBeInTheDocument();
      expect(screen.getByText("1.02")).toBeInTheDocument();
      expect(screen.getByText("2.01")).toBeInTheDocument();
    });

    it("should show overall pick number in parentheses", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("(#1)")).toBeInTheDocument();
      expect(screen.getByText("(#2)")).toBeInTheDocument();
      expect(screen.getByText("(#3)")).toBeInTheDocument();
    });

    it("should fall back to #pickNumber when numTeams is 0", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={0}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("#1")).toBeInTheDocument();
      expect(screen.getByText("#2")).toBeInTheDocument();
      expect(screen.getByText("#3")).toBeInTheDocument();
    });
  });

  describe("Participant Display", () => {
    it("should display all participant names in a single table", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Team A")).toBeInTheDocument();
      expect(screen.getByText("Driver B")).toBeInTheDocument();
      expect(screen.getByText("Team C")).toBeInTheDocument();
    });

    it("should show sport names as links to sport season pages", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      const nflLinks = screen.getAllByRole("link", { name: "NFL" });
      expect(nflLinks.length).toBeGreaterThanOrEqual(1);
      expect(nflLinks[0]).toHaveAttribute(
        "href",
        `/leagues/${mockLeagueId}/sports-seasons/ss-nfl`
      );

      const f1Link = screen.getByRole("link", { name: "F1" });
      expect(f1Link).toHaveAttribute(
        "href",
        `/leagues/${mockLeagueId}/sports-seasons/ss-f1`
      );
    });

    it("should show placement badges for completed participants", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("1st")).toBeInTheDocument();
      expect(screen.getByText("3rd")).toBeInTheDocument();
    });

    it("should show Pending badge for incomplete participants", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Pending")).toBeInTheDocument();
    });

    it("should show Did Not Score badge when finalPosition is 0", () => {
      const breakdownWithDNS = {
        ...mockBreakdown,
        picks: [
          {
            ...mockBreakdown.picks[0],
            finalPosition: 0,
            points: 0,
          },
        ],
      };

      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={breakdownWithDNS}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Did Not Score")).toBeInTheDocument();
    });

    it("should show Did Not Score badge when isComplete but finalPosition is null", () => {
      const breakdownWithNullPosition = {
        ...mockBreakdown,
        picks: [
          {
            ...mockBreakdown.picks[0],
            finalPosition: null,
            points: 0,
            isComplete: true,
            isPartialScore: false,
          },
        ],
      };

      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={breakdownWithNullPosition}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("Did Not Score")).toBeInTheDocument();
    });

    it("should show projected EV for incomplete participants", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      // Incomplete participant shows 0.00 (actual) and 25.00 (EV) in the row
      expect(screen.getByText("0.00")).toBeInTheDocument();
      expect(screen.getByText("25.00")).toBeInTheDocument();
    });

    it("should display 0.00 for completed picks with zero points", () => {
      const breakdownWithZero = {
        ...mockBreakdown,
        picks: [{ ...mockBreakdown.picks[0], finalPosition: 0, points: 0 }],
      };

      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={breakdownWithZero}
          standing={mockStanding}
        />
      );

      expect(screen.getByText("0.00")).toBeInTheDocument();
    });
  });

  describe("Navigation", () => {
    it("should have back to standings link", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      const backLink = screen.getByRole("link", { name: /back to standings/i });
      expect(backLink).toHaveAttribute(
        "href",
        `/leagues/${mockLeagueId}/standings/${mockSeasonId}`
      );
    });
  });

  describe("Sorting", () => {
    function getParticipantNames() {
      return screen
        .getAllByRole("row")
        .slice(1) // skip header row
        .map((row) => row.querySelectorAll("td")[2]?.textContent ?? "");
    }

    it("should default sort by pick number ascending", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      const names = getParticipantNames();
      expect(names).toEqual(["Team A", "Driver B", "Team C"]);
    });

    it("should sort by pick number descending on second click", async () => {
      const user = userEvent.setup();
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      const pickHeader = screen.getByRole("button", { name: /pick #/i });
      await user.click(pickHeader); // toggle to desc
      const names = getParticipantNames();
      expect(names).toEqual(["Team C", "Driver B", "Team A"]);
    });

    it("should sort by points descending on first click of Points header", async () => {
      const user = userEvent.setup();
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      // picks: Team A=100, Driver B=50, Team C=0
      const pointsHeader = screen.getByRole("button", { name: /points/i });
      await user.click(pointsHeader);
      const names = getParticipantNames();
      expect(names).toEqual(["Team A", "Driver B", "Team C"]);
    });

    it("should sort by points ascending on second click of Points header", async () => {
      const user = userEvent.setup();
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={mockStanding}
        />
      );

      const pointsHeader = screen.getByRole("button", { name: /points/i });
      await user.click(pointsHeader); // desc
      await user.click(pointsHeader); // asc
      const names = getParticipantNames();
      expect(names).toEqual(["Team C", "Driver B", "Team A"]);
    });

    it("should use projected points as tiebreaker when actual points are equal", async () => {
      const user = userEvent.setup();
      const tieBreakdown = {
        ...mockBreakdown,
        picks: [
          {
            pickNumber: 1,
            round: 1,
            participant: { id: "p1", name: "Alpha", sport: "NFL", sportsSeasonId: "ss-nfl" },
            finalPosition: null,
            points: 50,
            projectedPoints: 10,
            isComplete: false,
            isPartialScore: false,
          },
          {
            pickNumber: 2,
            round: 1,
            participant: { id: "p2", name: "Beta", sport: "NFL", sportsSeasonId: "ss-nfl" },
            finalPosition: null,
            points: 50,
            projectedPoints: 30,
            isComplete: false,
            isPartialScore: false,
          },
        ],
      };

      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={tieBreakdown}
          standing={mockStanding}
        />
      );

      const pointsHeader = screen.getByRole("button", { name: /points/i });
      await user.click(pointsHeader); // sort by points desc → Beta (50/30) before Alpha (50/10)
      const names = getParticipantNames();
      expect(names).toEqual(["Beta", "Alpha"]);
    });
  });

  describe("Without Standing Data", () => {
    it("should render without standing prop", () => {
      renderWithRouter(
        <TeamScoreBreakdown
          leagueId={mockLeagueId}
          seasonId={mockSeasonId}
          numTeams={numTeams}
          breakdown={mockBreakdown}
          standing={null}
        />
      );

      expect(screen.getByText("Test Team")).toBeInTheDocument();
      expect(screen.queryByText(/Rank #/)).not.toBeInTheDocument();
    });
  });
});
