import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
import { useQuery } from "@tanstack/react-query";

import { api } from "../api/client";
import type { TeamSnapEvent, TeamSnapMember } from "../api/types";
import { queryClient } from "../lib/queryClient";
import { findCurrentPlayer, findNextGame, sortGames } from "../lib/teamsnapHelpers";
import { teamSnapQueryKeys, teamsnapClient } from "../lib/teamsnap";
import { useSession } from "./useSession";

const TEAM_STORAGE_KEY = "walkup.selectedTeamId";

function readStoredTeamId(): string {
  if (typeof window === "undefined") {
    return "";
  }
  return window.localStorage.getItem(TEAM_STORAGE_KEY) ?? "";
}

type WalkupContextValue = ReturnType<typeof useBuildWalkupContext>;

const WalkupContext = createContext<WalkupContextValue | null>(null);

function useBuildWalkupContext() {
  const sessionQuery = useSession();
  const isTeamSnap = sessionQuery.data?.authenticated === true && sessionQuery.data?.provider === "teamsnap";
  const teamSnapCacheScope = isTeamSnap
    ? String(sessionQuery.data?.external_user_id ?? sessionQuery.data?.external_team_id ?? "teamsnap")
    : "anonymous";
  const [selectedTeamId, setSelectedTeamId] = useState(readStoredTeamId);
  const teamsQuery = useQuery({
    queryKey: teamSnapQueryKeys.teams(teamSnapCacheScope),
    queryFn: () => teamsnapClient.loadTeams(teamSnapCacheScope),
    enabled: isTeamSnap,
    networkMode: "always",
    retry: 0,
  });

  const teams = teamsQuery.data ?? [];
  const selectedTeam = teams.find((team) => String(team.id) === selectedTeamId) ?? null;
  const resolvedTeamId = selectedTeam ? String(selectedTeam.id) : "";

  useEffect(() => {
    if (selectedTeamId && !selectedTeam && teams.length) {
      setSelectedTeamId("");
      window.localStorage.removeItem(TEAM_STORAGE_KEY);
      return;
    }

    if (!selectedTeamId) {
      window.localStorage.removeItem(TEAM_STORAGE_KEY);
      return;
    }

    window.localStorage.setItem(TEAM_STORAGE_KEY, selectedTeamId);
  }, [resolvedTeamId, selectedTeam, selectedTeamId, teams.length]);

  const membersQuery = useQuery({
    queryKey: teamSnapQueryKeys.members(teamSnapCacheScope, resolvedTeamId),
    queryFn: () => teamsnapClient.loadMembers(resolvedTeamId, teamSnapCacheScope),
    enabled: isTeamSnap && Boolean(resolvedTeamId),
    networkMode: "always",
    retry: 0,
  });
  const eventsQuery = useQuery({
    queryKey: teamSnapQueryKeys.events(teamSnapCacheScope, resolvedTeamId),
    queryFn: () => teamsnapClient.loadEvents(resolvedTeamId, teamSnapCacheScope),
    enabled: isTeamSnap && Boolean(resolvedTeamId),
    networkMode: "always",
    retry: 0,
  });

  const members: TeamSnapMember[] = membersQuery.data ?? [];
  const games: TeamSnapEvent[] = sortGames(eventsQuery.data ?? []);
  const currentPlayer = findCurrentPlayer(sessionQuery.data?.external_user_id, members);
  const nextGame = findNextGame(games);
  const currentPlayerId =
    sessionQuery.data?.external_team_id === selectedTeamId && sessionQuery.data?.external_player_id
      ? String(sessionQuery.data.external_player_id)
      : currentPlayer
        ? String(currentPlayer.id)
        : "";

  useEffect(() => {
    if (!isTeamSnap || !resolvedTeamId || !currentPlayer) {
      return;
    }

    const selectedPlayerId = String(currentPlayer.id);
    if (
      sessionQuery.data?.external_team_id === selectedTeamId &&
      sessionQuery.data?.external_player_id === selectedPlayerId
    ) {
      return;
    }

    void api
      .updateWalkupSessionSelection({
        external_team_id: resolvedTeamId,
        external_player_id: selectedPlayerId,
      })
      .then(async () => {
        await queryClient.invalidateQueries({ queryKey: ["session"] });
      })
      .catch(() => {
        // Keep the UI working even if the session cache update fails.
      });
  }, [currentPlayer, isTeamSnap, resolvedTeamId, selectedTeamId, sessionQuery.data?.external_player_id, sessionQuery.data?.external_team_id]);

  function selectTeam(teamId: string) {
    setSelectedTeamId(teamId);
  }

  return {
    isTeamSnap,
    sessionQuery,
    teamsQuery,
    teamSnapCacheScope,
    selectedTeam,
    selectedTeamId,
    hasSelectedTeam: Boolean(resolvedTeamId),
    selectTeam,
    membersQuery,
    members,
    currentPlayer,
    currentPlayerId,
    eventsQuery,
    games,
    nextGame,
  };
}

export function WalkupProvider({ children }: { children: ReactNode }) {
  const value = useBuildWalkupContext();
  const memoizedValue = useMemo(() => value, [value]);
  return <WalkupContext.Provider value={memoizedValue}>{children}</WalkupContext.Provider>;
}

export function useWalkupContext() {
  const value = useContext(WalkupContext);
  if (!value) {
    throw new Error("useWalkupContext must be used within WalkupProvider");
  }
  return value;
}
