import { useEffect } from "react";
import { useSearchParams } from "react-router";
import { toast } from "sonner";
import { auth } from "~/lib/auth.server";
import { addDays, subDays } from "date-fns";

import type { Route } from "./+types/home";
import { LandingPage } from "~/components/marketing/LandingPage";
import { findLeaguesWithActiveSeasonsByUserId } from "~/models/league";
import { findSeasonById, findCurrentSeasonWithSports } from "~/models/season";
import { findTeamByOwnerAndSeason } from "~/models/team";
import { getDraftedParticipantsBySportsSeason } from "~/models/draft-pick";
import { getUpcomingEventsForDraftedParticipants } from "~/models/scoring-event";
import { getTeamStanding, getSeasonStandings } from "~/models/standings";
import { getSeasonCompletionPercentage } from "~/lib/season-helpers.server";
import { buildTiedRankChecker, getDisplayRank } from "~/lib/standings-display";
import { findDraftSlotsBySeasonId } from "~/models/draft-slot";
import { getTeamForPick } from "~/lib/draft-order";
import type { CalendarPanelEvent } from "~/components/sport-season/UpcomingCalendarPanel";
import { UpcomingEventsCard } from "~/components/sport-season/UpcomingEventsCard";
import { MyLeaguesCard } from "~/components/league/MyLeaguesCard";
import { CreateLeagueCard } from "~/components/league/CreateLeagueCard";
import type { LeagueRowProps } from "~/components/league/LeagueRow";
import { toEventSortKey } from "~/lib/date-utils";

export function meta() {
  return [
    { title: "Brackt - Fantasy All of the Sports!" },
    {
      name: "description",
      content: "Play multi-sport fantasy leagues with your friends!",
    },
  ];
}

export async function loader(args: Route.LoaderArgs) {
  const session = await auth.api.getSession({ headers: args.request.headers });
  const userId = session?.user.id ?? null;

  if (!userId) {
    return { leagues: [], isLoggedIn: false, upcomingCalendarEvents: [] };
  }

  const leagues = await findLeaguesWithActiveSeasonsByUserId(userId);

  const today = new Date();
  const dateFromStr = subDays(today, 1).toISOString().split("T")[0];
  const dateToStr = addDays(today, 30).toISOString().split("T")[0];

  const leaguesWithData = await Promise.all(
    leagues.map(async (league) => {
      const [season, seasonWithSports] = await Promise.all([
        league.currentSeasonId ? findSeasonById(league.currentSeasonId) : null,
        findCurrentSeasonWithSports(league.id),
      ]);

      const numSports = seasonWithSports?.seasonSports?.length ?? 0;
      const calendarEvents: CalendarPanelEvent[] = [];
      let currentRank: number | undefined;
      let totalPoints: number | undefined;
      let previousRank: number | undefined;
      let displayRank: string | number | undefined;
      let completionPercentage = 0;
      let picksUntilMyTurn: number | undefined;
      let draftPosition: number | undefined;
      // False when there's no current season — a commish with no season has no team by definition.
      let hasTeam = false;

      if (league.currentSeasonId && seasonWithSports?.seasonSports) {
        const myTeam = await findTeamByOwnerAndSeason(userId, league.currentSeasonId);
        hasTeam = !!myTeam;

        if (myTeam) {
          // Fetch standing, completion %, and calendar events in parallel
          const [standing, pct, participantsBySportsSeason] = await Promise.all([
            getTeamStanding(myTeam.id, league.currentSeasonId),
            getSeasonCompletionPercentage(league.currentSeasonId),
            getDraftedParticipantsBySportsSeason(myTeam.id, league.currentSeasonId),
          ]);

          completionPercentage = pct;

          // Draft slot info — needed for pre-draft position and in-progress picks-until-turn
          if (season?.status === "draft" || season?.status === "pre_draft") {
            const draftSlots = await findDraftSlotsBySeasonId(league.currentSeasonId);
            const mySlot = draftSlots.find((s) => s.teamId === myTeam.id);
            if (mySlot) {
              draftPosition = mySlot.draftOrder;
            }
            if (season.status === "draft" && season.currentPickNumber) {
              const currentPick = season.currentPickNumber;
              let offset = 0;
              // Snake draft: one full cycle is draftSlots.length * 2 picks
              while (offset < draftSlots.length * 2) {
                const slot = getTeamForPick(currentPick + offset, draftSlots);
                if (slot?.teamId === myTeam.id) {
                  picksUntilMyTurn = offset;
                  break;
                }
                offset++;
              }
            }
          }

          if (standing) {
            currentRank = standing.currentRank ?? undefined;
            totalPoints = standing.totalPoints ?? undefined;
            previousRank = standing.previousRank ?? undefined;
            const allStandings = await getSeasonStandings(league.currentSeasonId);
            const isTied = buildTiedRankChecker(allStandings.map((s) => s.currentRank));
            displayRank = getDisplayRank(standing, allStandings.length, isTied(standing.currentRank));
          } else if (myTeam && season?.status === "active") {
            // No standing row yet (no scoring events) — default to rank 1, 0 points
            currentRank = 1;
            totalPoints = 0;
          }

          const perSeasonEvents = await Promise.all(
            seasonWithSports.seasonSports.map(async ({ sportsSeason: ss }) => {
              const draftedParticipants = participantsBySportsSeason.get(ss.id) ?? [];
              if (draftedParticipants.length === 0) return [];

              const events = await getUpcomingEventsForDraftedParticipants(
                ss.id,
                ss.scoringPattern ?? "",
                draftedParticipants,
                dateFromStr,
                dateToStr
              );

              return events.map((event) => ({
                ...event,
                sportName: ss.sport.name,
                sportSeasonName: ss.name,
                leagueName: league.name,
                leagueId: league.id,
                sportsSeasonPageUrl: `/leagues/${league.id}/sports-seasons/${ss.id}`,
              }));
            })
          );

          calendarEvents.push(...perSeasonEvents.flat());
        }
      }

      return {
        ...league,
        currentSeason: season,
        numSports,
        displayRank,
        currentRank,
        totalPoints,
        previousRank,
        completionPercentage,
        picksUntilMyTurn,
        draftPosition,
        draftDateTime: season?.draftDateTime?.toISOString() ?? null,
        calendarEvents,
        hasTeam,
      };
    })
  );

  const upcomingCalendarEvents = leaguesWithData
    .flatMap((l) => l.calendarEvents)
    .toSorted((a, b) => toEventSortKey(a).localeCompare(toEventSortKey(b)));

  return {
    leagues: leaguesWithData,
    isLoggedIn: true,
    upcomingCalendarEvents,
  };
}

const VALID_STATUSES = ["draft", "active", "pre_draft", "completed"] as const;
type ValidStatus = (typeof VALID_STATUSES)[number];
function isValidStatus(s: string): s is ValidStatus {
  return VALID_STATUSES.includes(s as ValidStatus);
}

export default function Home({ loaderData }: Route.ComponentProps) {
  const { leagues, isLoggedIn, upcomingCalendarEvents } = loaderData;
  const [searchParams, setSearchParams] = useSearchParams();

  useEffect(() => {
    if (searchParams.get("deleted") === "true") {
      toast.success("League deleted successfully");
      setSearchParams({});
    }
    if (searchParams.get("left") === "true") {
      toast.success("You have left the league. Your team is now available.");
      setSearchParams({});
    }
  }, [searchParams, setSearchParams]);

  if (!isLoggedIn) {
    return <LandingPage />;
  }

  const leagueRows: LeagueRowProps[] = leagues.map((league) => {
    const rawStatus = league.currentSeason?.status ?? "pre_draft";
    return {
      leagueId: league.id,
      leagueName: league.name,
      numSports: league.numSports,
      status: isValidStatus(rawStatus) ? rawStatus : "pre_draft",
      seasonId: league.currentSeasonId ?? undefined,
      currentRank: league.currentRank,
      displayRank: league.displayRank,
      totalPoints: league.totalPoints,
      previousRank: league.previousRank,
      completionPercentage: league.completionPercentage,
      picksUntilMyTurn: league.picksUntilMyTurn,
      draftPosition: league.draftPosition,
      draftDateTime: league.draftDateTime,
      isCommishOnly: !league.hasTeam,
    };
  });

  return (
    <div className="container mx-auto py-8 px-4">
      {/*
        lg+: flex row, left column (My Leagues + Create) takes 2/3, right (Events) takes 1/3.
        mobile/tablet: single column stacked in order: My Leagues, Upcoming Events, Create League.
      */}
      <div className="flex flex-col gap-6 lg:flex-row">
        <div className="flex flex-col gap-6 lg:w-2/3">
          <MyLeaguesCard leagues={leagueRows} />
          <div className="lg:hidden">
            <UpcomingEventsCard
              events={upcomingCalendarEvents}
              limit={8}
              viewAllUrl="/upcoming-events"
              showLeagueAvatar={leagueRows.length > 1}
            />
          </div>
          <CreateLeagueCard />
        </div>
        <div className="hidden lg:block lg:w-1/3">
          <UpcomingEventsCard
            events={upcomingCalendarEvents}
            limit={8}
            viewAllUrl="/upcoming-events"
            showLeagueAvatar={leagueRows.length > 1}
          />
        </div>
      </div>
    </div>
  );
}
