import { useLoaderData, Link, useRevalidator, redirect, useNavigate } from "react-router";
import { useDraftSocket } from "~/hooks/useDraftSocket";
import { logger } from "~/lib/logger";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Button } from "~/components/ui/button";
import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { auth } from "~/lib/auth.server";
import { useDraftRoomState, type QueueItem } from "~/hooks/useDraftRoomState";
import { useDraftAuthRecovery } from "~/hooks/useDraftAuthRecovery";
import { useDraftSocketEvents } from "~/hooks/useDraftSocketEvents";
import { RollbackConfirmDialog } from "~/components/draft/RollbackConfirmDialog";
import { TimeBankAdjustmentDialog } from "~/components/draft/TimeBankAdjustmentDialog";
import { CommissionerAutodraftDialog } from "~/components/draft/CommissionerAutodraftDialog";
import { CommissionerDraftControls } from "~/components/draft/CommissionerDraftControls";
import { getTeamQueue } from "~/models/draft-queue";
import { getTeamWatchlist } from "~/models/watchlist";
import { findSeasonWithTeamsAndLeague } from "~/models/season";
import { findDraftSlotsBySeasonId } from "~/models/draft-slot";
import { getDraftPicksForSeason } from "~/models/draft-pick";
import { getDraftParticipants } from "~/models/season-participant";
import { getSeasonTimers } from "~/models/draft-timer";
import { getSeasonAutodraftSettings } from "~/models/autodraft-settings";
import { hasCommissionerRecord } from "~/models/commissioner";
import { findUsersByIds, getUserDisplayName } from "~/models/user";
import { resolveUserAvatarData } from "~/lib/avatar-data";
import { isInOvernightWindow } from "~/lib/overnight-pause";
import logomarkUrl from "../../../public/logomark.svg?url";
import { DraftSidebar } from "~/components/DraftSidebar";
import { TeamRosterView } from "~/components/draft/TeamRosterView";
import { DraftSummaryView } from "~/components/draft/DraftSummaryView";
import { QueueSection } from "~/components/draft/QueueSection";
import { AvailableParticipantsSection } from "~/components/draft/AvailableParticipantsSection";
import { SidebarRecentPicks } from "~/components/draft/SidebarRecentPicks";
import { RecentPicksFeed } from "~/components/draft/RecentPicksFeed";
import { DraftGridSection } from "~/components/draft/DraftGridSection";
import { ConnectionOverlay } from "~/components/draft/ConnectionOverlay";
import { AuthRecoveryOverlay } from "~/components/draft/AuthRecoveryOverlay";
import { ParticipantSelectionDialog } from "~/components/draft/ParticipantSelectionDialog";
import { calculateDraftEligibility } from "~/lib/draft-eligibility";
import { getTeamForPick, getProjectedPicks } from "~/lib/draft-order";
import { useDraftNotifications } from "~/hooks/useDraftNotifications";
import { NotificationSettings } from "~/components/NotificationSettings";
import { AutodraftBadgeWithPopover, AutodraftSettings } from "~/components/AutodraftSettings";
import { toast } from "sonner";
import { formatClockTime, getTimerColorClass } from "~/lib/draft-timer";
import { Users, LayoutGrid, ListChecks, Settings, ListOrdered } from "lucide-react";
import type { Route } from "./+types/$leagueId.draft.$seasonId";

export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors {
  return [{ title: `Draft — ${data?.season?.league?.name ?? "League"} - Brackt` }];
}

const MOBILE_TABS_BASE = [
  { id: "available" as const, label: "Participants", Icon: Users },
  { id: "board" as const, label: "Board", Icon: LayoutGrid },
  { id: "teams" as const, label: "Teams", Icon: ListChecks },
  { id: "controls" as const, label: "Controls", Icon: Settings },
];

const QUEUE_TAB = { id: "queue" as const, label: "Queue", Icon: ListOrdered };

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

  if (!seasonId) {
    throw new Response("Season ID is required", { status: 400 });
  }

  const season = await findSeasonWithTeamsAndLeague(seasonId);

  if (!season) {
    throw new Response("Season not found", { status: 404 });
  }

  if (season.draftCompletedAt) {
    const elapsed = Date.now() - season.draftCompletedAt.getTime();
    if (elapsed >= 5 * 60 * 1000) {
      return redirect(`/leagues/${leagueId}/draft-board/${seasonId}`);
    }
  }

  const userTeam = userId
    ? season.teams.find((team) => team.ownerId === userId)
    : undefined;

  const isCommissioner = userId
    ? await hasCommissionerRecord(leagueId, userId)
    : false;

  if (!season.league.isPublicDraftBoard) {
    if (!userId) {
      throw new Response("You must be logged in to view the draft room", {
        status: 401,
      });
    }
    if (!userTeam && !isCommissioner) {
      throw new Response("You do not have access to this draft room", {
        status: 403,
      });
    }
  }

  const [draftSlots, draftPicks, availableParticipants, timers, autodraftSettings] =
    await Promise.all([
      findDraftSlotsBySeasonId(seasonId),
      getDraftPicksForSeason(seasonId),
      getDraftParticipants(seasonId),
      getSeasonTimers(seasonId),
      getSeasonAutodraftSettings(seasonId),
    ]);

  const userQueue = userTeam
    ? await getTeamQueue(userTeam.id).catch((err) => {
        logger.error("[DraftLoader] Failed to load queue, defaulting to empty:", err);
        return [];
      })
    : [];

  const userWatchlist = userTeam
    ? await getTeamWatchlist(userTeam.id, seasonId).catch((err) => {
        logger.error("[DraftLoader] Failed to load watchlist, defaulting to empty:", err);
        return [];
      })
    : [];

  const userAutodraftSettings = userTeam
    ? (autodraftSettings.find((s) => s.teamId === userTeam.id) ?? null)
    : null;

  // Single users query builds both the owner display-name map and the timezone
  // map for overnight pause moon icons — avoids two separate findUsersByIds calls.
  const uniqueOwnerIds = [...new Set(
    draftSlots.map((s) => s.team.ownerId).filter((id): id is string => id !== null)
  )];
  const userRows = uniqueOwnerIds.length ? await findUsersByIds(uniqueOwnerIds) : [];
  const userById = new Map(userRows.map((u) => [u.id, u]));

  const ownerMap: Record<string, string> = {};
  for (const slot of draftSlots) {
    if (slot.team.ownerId) {
      const user = userById.get(slot.team.ownerId);
      const name = user ? getUserDisplayName(user) : null;
      if (name) ownerMap[slot.team.id] = name;
    }
  }

  const teamTimezoneMap: Record<string, string | null> =
    season.overnightPauseMode === "per_user"
      ? Object.fromEntries(
          draftSlots.map((slot) => [
            slot.team.id,
            slot.team.ownerId ? (userById.get(slot.team.ownerId)?.timezone || null) : null,
          ])
        )
      : {};

  const enrichedDraftSlots = draftSlots.map((slot) => {
    const ownerUser = slot.team.ownerId ? userById.get(slot.team.ownerId) : undefined;
    return {
      ...slot,
      team: {
        ...slot.team,
        ownerAvatarData: ownerUser ? resolveUserAvatarData(ownerUser) : null,
      },
    };
  });

  return {
    season,
    draftSlots: enrichedDraftSlots,
    draftPicks,
    availableParticipants,
    userTeam,
    userQueue,
    userWatchlist: userWatchlist.map((w) => w.participantId),
    timers,
    autodraftSettings,
    userAutodraftSettings,
    isCommissioner: !!isCommissioner,
    currentUserId: userId,
    ownerMap,
    teamTimezoneMap,
  };
}

export default function DraftRoom() {
  const {
    season,
    draftSlots,
    draftPicks,
    availableParticipants: initialAvailableParticipants,
    userTeam,
    userQueue,
    userWatchlist,
    timers,
    autodraftSettings,
    userAutodraftSettings,
    isCommissioner,
    currentUserId,
    ownerMap,
    teamTimezoneMap,
  } = useLoaderData<typeof loader>();
  const availableParticipants = initialAvailableParticipants;
  const [bracktVorps, setBracktVorps] = useState<Map<string, number>>(() => new Map());
  const sortedAvailableParticipants = useMemo(() => {
    if (bracktVorps.size === 0) return availableParticipants;
    return availableParticipants.toSorted((a, b) => {
      const aVorp = bracktVorps.get(a.id) ?? parseFloat(a.vorpValue ?? "0");
      const bVorp = bracktVorps.get(b.id) ?? parseFloat(b.vorpValue ?? "0");
      const diff = bVorp - aVorp;
      return diff !== 0 ? diff : a.name.localeCompare(b.name);
    });
  }, [availableParticipants, bracktVorps]);
  const navigate = useNavigate();
  const { revalidate, state: revalidatorState } = useRevalidator();
  const { isConnected, connectionError, isReconnecting, reconnectCount, socketVersion, on, off } = useDraftSocket(season.id, userTeam?.id);
  const {
    permissionState: notificationsPermission,
    enabled: notificationsEnabled,
    setEnabled: setNotificationsEnabled,
    mode: notificationsMode,
    setMode: setNotificationsMode,
    sendNotification,
  } = useDraftNotifications(season.id, currentUserId ?? "");

  // Use refs so the socket effect doesn't re-register all handlers when the user
  // changes notification settings (which would change the sendNotification reference).
  const sendNotificationRef = useRef(sendNotification);
  useEffect(() => {
    sendNotificationRef.current = sendNotification;
  }, [sendNotification]);
  const notificationsModeRef = useRef(notificationsMode);
  useEffect(() => {
    notificationsModeRef.current = notificationsMode;
  }, [notificationsMode]);

  const {
    picks, setPicks,
    currentPick, setCurrentPick,
    searchQuery, setSearchQuery,
    hideDrafted, setHideDrafted,
    hideIneligible, setHideIneligible,
    hideCompletedSports, setHideCompletedSports,
    sportFilters, setSportFilters,
    queue, setQueue,
    isPaused, setIsPaused,
    isDraftComplete, setIsDraftComplete,
    sidebarCollapsed, setSidebarCollapsed,
    activeTab, setActiveTab,
    mobileTab, setMobileTab,
    teamsSubTab, setTeamsSubTab,
    boardSubTab, setBoardSubTab,
    isMobile,
    autodraftStatus, setAutodraftStatus,
    connectedTeams, setConnectedTeams,
    watchedParticipantIds, setWatchedParticipantIds,
    showOnlyWatched, setShowOnlyWatched,
    teamTimers, setTeamTimers,
    forcePickDialogOpen, setForcePickDialogOpen,
    selectedPickSlot, setSelectedPickSlot,
    replacePickDialogOpen, setReplacePickDialogOpen,
    replacePickSlot, setReplacePickSlot,
    rollbackConfirmOpen, setRollbackConfirmOpen,
    rollbackPickNumber, setRollbackPickNumber,
    isRollingBack, setIsRollingBack,
    timeBankDialogOpen, setTimeBankDialogOpen,
    timeBankTeamId, setTimeBankTeamId,
    commissionerAutodraftDialogOpen, setCommissionerAutodraftDialogOpen,
    commissionerAutodraftTeamId, setCommissionerAutodraftTeamId,
    timeBankAmount, setTimeBankAmount,
    timeBankUnit, setTimeBankUnit,
    timeBankDirection, setTimeBankDirection,
    isAdjustingTimeBank, setIsAdjustingTimeBank,
    isOvernightPause, setIsOvernightPause,
    overnightResumesAt, setOvernightResumesAt,
    roomClosed, setRoomClosed,
    isSyncing, setIsSyncing,
  } = useDraftRoomState({
    draftPicks,
    season,
    userTeam,
    isCommissioner,
    autodraftSettings,
    timers,
    draftSlots,
    userQueue,
    initialWatchedParticipantIds: userWatchlist,
  });

  // Advances every second so isInOvernightWindow sees the real current time.
  const [nowForPauseCheck, setNowForPauseCheck] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setNowForPauseCheck(new Date()), 1_000);
    return () => clearInterval(id);
  }, []);

  const secondsUntilAutoStart = useMemo(() => {
    if (season.status !== "pre_draft" || !season.autoStartDraft || !season.draftDateTime) return null;
    const diff = Math.ceil((new Date(season.draftDateTime).getTime() - nowForPauseCheck.getTime()) / 1000);
    return diff > 0 ? diff : 0;
  }, [season.status, season.autoStartDraft, season.draftDateTime, nowForPauseCheck]);

  const draftBoardUrl = `/leagues/${season.leagueId}/draft-board/${season.id}`;
  const roomClosureCountdown = useMemo(() => {
    if (!isDraftComplete) return null;
    const completedAt = season.draftCompletedAt;
    if (!completedAt) return 300;
    const elapsed = (nowForPauseCheck.getTime() - completedAt.getTime()) / 1000;
    const remaining = Math.max(0, 300 - elapsed);
    return Math.ceil(remaining);
  }, [isDraftComplete, season.draftCompletedAt, nowForPauseCheck]);

  useEffect(() => {
    if (!isDraftComplete) return;
    if (roomClosed) {
      navigate(draftBoardUrl);
      return;
    }
    if (roomClosureCountdown !== null && roomClosureCountdown <= 0) {
      navigate(draftBoardUrl);
    }
  }, [isDraftComplete, roomClosed, roomClosureCountdown, navigate, draftBoardUrl]);

  // Compute which teams are currently in their overnight pause window.
  const pausedTeamIds = useMemo(() => {
    const { overnightPauseMode: mode, overnightPauseStart: start, overnightPauseEnd: end, overnightPauseTimezone: fallbackTz } = season;
    if (mode === "none" || !start || !end) return new Set<string>();
    const result = new Set<string>();
    for (const slot of draftSlots) {
      const tz = mode === "league"
        ? (fallbackTz || null)
        : (teamTimezoneMap[slot.team.id] || fallbackTz || null);
      if (tz && isInOvernightWindow(tz, start, end, nowForPauseCheck)) result.add(slot.team.id);
    }
    return result;
  }, [season, draftSlots, teamTimezoneMap, nowForPauseCheck]);

  const {
    authDegraded,
    authFetch,
    userAutodraft,
    setUserAutodraft,
    userAutodraftRef,
    isRevalidatingRef,
    pendingPicksDuringRevalidationRef,
    pendingQueueMutationsRef,
  } = useDraftAuthRecovery({
    reconnectCount,
    revalidate,
    revalidatorState,
    currentUserId,
    userAutodraftSettings,
    draftPicks,
    season,
    userQueue,
    timers,
    autodraftSettings,
    setPicks,
    setCurrentPick,
    setIsPaused,
    setIsDraftComplete,
    setQueue,
    setTeamTimers,
    setAutodraftStatus,
    setIsSyncing,
  });

  useEffect(() => {
    if (reconnectCount <= 0) return;
    setIsSyncing(true);
    const id = setTimeout(() => setIsSyncing(false), 5000);
    return () => clearTimeout(id);
  }, [reconnectCount, setIsSyncing]);

  // Shared transforms for eligibility calculations
  const transformedPicks = useMemo(
    () =>
      picks.map((p) => ({
        teamId: p.team.id,
        participant: {
          id: p.participant.id,
          sport: { id: p.sport.id, name: p.sport.name },
        },
      })),
    [picks]
  );

  const transformedParticipants = useMemo(
    () =>
      availableParticipants.map((p) => ({
        id: p.id,
        sport: { id: p.sport.id, name: p.sport.name },
      })),
    [availableParticipants]
  );

  const seasonSportsData = useMemo(() => {
    const sportsMap = new Map<string, { id: string; name: string }>();
    availableParticipants.forEach((p) => {
      if (!sportsMap.has(p.sport.id)) {
        sportsMap.set(p.sport.id, { id: p.sport.id, name: p.sport.name });
      }
    });
    return Array.from(sportsMap.values()).toSorted((a, b) =>
      a.name.localeCompare(b.name)
    );
  }, [availableParticipants]);

  const participantRanks = useMemo(() => {
    const ranks = new Map<string, { overallRank: number; sportRank: number }>();
    const sportCounters = new Map<string, number>();
    sortedAvailableParticipants.forEach((p, i) => {
      const sportIdx = (sportCounters.get(p.sport.id) ?? 0) + 1;
      sportCounters.set(p.sport.id, sportIdx);
      ranks.set(p.id, { overallRank: i + 1, sportRank: sportIdx });
    });
    return ranks;
  }, [sortedAvailableParticipants]);

  // Calculate draft eligibility for current user's team
  const eligibility = useMemo(() => {
    if (!userTeam) return null;
    const userTeamPicks = transformedPicks.filter(
      (p) => p.teamId === userTeam.id
    );
    return calculateDraftEligibility(
      userTeam.id,
      userTeamPicks,
      transformedPicks,
      transformedParticipants,
      seasonSportsData,
      season.draftRounds,
      season.teams
    );
  }, [userTeam, transformedPicks, transformedParticipants, seasonSportsData, season]);

  // Calculate eligibility for force manual pick dialog (selected team)
  const forcePickEligibility = useMemo(() => {
    if (!selectedPickSlot) return null;
    const selectedTeamPicks = transformedPicks.filter(
      (p) => p.teamId === selectedPickSlot.teamId
    );
    return calculateDraftEligibility(
      selectedPickSlot.teamId,
      selectedTeamPicks,
      transformedPicks,
      transformedParticipants,
      seasonSportsData,
      season.draftRounds,
      season.teams
    );
  }, [selectedPickSlot, transformedPicks, transformedParticipants, seasonSportsData, season]);

  // Calculate eligibility for replace pick dialog — exclude the old pick so its slot is free
  const replacePickEligibility = useMemo(() => {
    if (!replacePickSlot) return null;
    const allPicksExcluding = transformedPicks.filter(
      (p) => p.participant.id !== replacePickSlot.oldParticipantId
    );
    const selectedTeamPicks = allPicksExcluding.filter(
      (p) => p.teamId === replacePickSlot.teamId
    );
    return calculateDraftEligibility(
      replacePickSlot.teamId,
      selectedTeamPicks,
      allPicksExcluding,
      transformedParticipants,
      seasonSportsData,
      season.draftRounds,
      season.teams
    );
  }, [replacePickSlot, transformedPicks, transformedParticipants, seasonSportsData, season]);

  const [animatingOutParticipantIds, setAnimatingOutParticipantIds] = useState<Set<string>>(new Set());
  const [pickAnimationSignal, setPickAnimationSignal] = useState<{ id: string; seq: number } | null>(null);
  const pickSeqRef = useRef(0);
  const animationTimersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());
  const addAnimatingOut = useCallback((id: string) => {
    setAnimatingOutParticipantIds((prev) => new Set([...prev, id]));
    pickSeqRef.current += 1;
    setPickAnimationSignal({ id, seq: pickSeqRef.current });
    const timer = setTimeout(() => {
      setAnimatingOutParticipantIds((prev) => {
        const next = new Set(prev);
        next.delete(id);
        return next;
      });
      animationTimersRef.current.delete(timer);
    }, 650);
    animationTimersRef.current.add(timer);
  }, []);
  useEffect(() => () => { animationTimersRef.current.forEach(clearTimeout); }, []);

  useDraftSocketEvents({
    on,
    off,
    socketVersion,
    userTeam,
    draftSlots,
    leagueName: season.league.name,
    isRevalidatingRef,
    pendingPicksDuringRevalidationRef,
    pendingQueueMutationsRef,
    userAutodraftRef,
    sendNotificationRef,
    notificationsModeRef,
    setPicks,
    setCurrentPick,
    setIsPaused,
    setIsDraftComplete,
    setAutodraftStatus,
    setUserAutodraft,
    setConnectedTeams,
    setQueue,
    setTeamTimers,
    setIsOvernightPause,
    setOvernightResumesAt,
    setWatchedParticipantIds,
    setRoomClosed,
    setIsSyncing,
    setBracktVorps,
    setAnimatingOutParticipantId: addAnimatingOut,
  });

  // Persist sidebar collapsed state
  useEffect(() => {
    if (typeof window !== "undefined") {
      localStorage.setItem("draftSidebarCollapsed", JSON.stringify(sidebarCollapsed));
    }
  }, [sidebarCollapsed]);

  // Queue handlers
  const handleAddToQueue = useCallback(async (participantId: string) => {
    if (!userTeam) return;

    // Check if participant is already in queue (client-side)
    const alreadyInQueue = queue.some((item) => item.participantId === participantId);
    if (alreadyInQueue) {
      toast.error("This participant is already in your queue");
      return;
    }

    // Optimistic update - create a temporary queue item
    const now = new Date();
    const tempQueueItem: QueueItem = {
      id: `temp-${Date.now()}`,
      participantId,
      queuePosition: queue.length + 1,
      seasonId: season.id,
      teamId: userTeam.id,
      createdAt: now,
      updatedAt: now,
    };

    // Immediately update the UI
    setQueue((prev) => [...prev, tempQueueItem]);

    const formData = new FormData();
    formData.append("seasonId", season.id);
    formData.append("teamId", userTeam.id);
    formData.append("participantId", participantId);

    pendingQueueMutationsRef.current++;
    try {
      const response = await authFetch("/api/queue/add", {
        method: "POST",
        body: formData,
      });
      if (!response) { setQueue((prev) => prev.filter((item) => item.id !== tempQueueItem.id)); return; }

      if (response.ok) {
        const data = await response.json();
        // Replace temp item with real item from server
        setQueue((prev) =>
          prev.map((item) =>
            item.id === tempQueueItem.id ? data.queueItem : item
          )
        );
      } else {
        // Revert the optimistic update on error
        setQueue((prev) => prev.filter((item) => item.id !== tempQueueItem.id));
        const error = await response.json();
        toast.error(error.error || "Failed to add to queue");
      }
    } catch {
      // Revert the optimistic update on network error
      setQueue((prev) => prev.filter((item) => item.id !== tempQueueItem.id));
      toast.error("Network error - failed to add to queue");
    } finally {
      pendingQueueMutationsRef.current--;
    }
  // queue is read directly (not via functional updater) for the duplicate check and
  // optimistic position, so it must be a dep. This is fine: AvailableParticipantsSection
  // already re-renders when queue changes (it receives queue as a prop).
  }, [userTeam, queue, season.id, authFetch, setQueue, pendingQueueMutationsRef]);

  const handleRemoveFromQueue = useCallback(async (queueId: string) => {
    if (!userTeam) return;

    // Optimistically remove the item immediately
    let previousQueue: QueueItem[] = [];
    setQueue((prev) => {
      previousQueue = prev;
      return prev.filter((item) => item.id !== queueId);
    });

    const formData = new FormData();
    formData.append("queueId", queueId);
    formData.append("teamId", userTeam.id);

    pendingQueueMutationsRef.current++;
    try {
      const response = await authFetch("/api/queue/remove", {
        method: "POST",
        body: formData,
      });
      if (!response) { setQueue(previousQueue); return; }

      if (response.ok) {
        const data = await response.json();
        setQueue(data.queue);
      } else {
        setQueue(previousQueue);
        const error = await response.json();
        toast.error(error.error || "Failed to remove from queue");
      }
    } catch {
      setQueue(previousQueue);
      toast.error("Network error - failed to remove from queue");
    } finally {
      pendingQueueMutationsRef.current--;
    }
  }, [userTeam, authFetch, setQueue, pendingQueueMutationsRef]);

  const handleReorderQueue = useCallback(async (participantIds: string[]) => {
    if (!userTeam) return;

    // Optimistically reorder the queue immediately
    let previousQueue: QueueItem[] = [];
    setQueue((prev) => {
      previousQueue = prev;
      return participantIds
        .map((pid) => prev.find((item) => item.participantId === pid))
        .filter((item): item is QueueItem => item !== undefined);
    });

    const formData = new FormData();
    formData.append("teamId", userTeam.id);
    formData.append("seasonId", season.id);
    formData.append("participantIds", JSON.stringify(participantIds));

    pendingQueueMutationsRef.current++;
    try {
      const response = await authFetch("/api/queue/reorder", {
        method: "POST",
        body: formData,
      });
      if (!response) { setQueue(previousQueue); return; }

      if (response.ok) {
        const data = await response.json();
        setQueue(data.queue);
      } else {
        const error = await response.json();
        setQueue(previousQueue);
        toast.error(error.error || "Failed to reorder queue");
      }
    } catch {
      setQueue(previousQueue);
      toast.error("Network error - failed to reorder queue");
    } finally {
      pendingQueueMutationsRef.current--;
    }
  }, [userTeam, season.id, authFetch, setQueue, pendingQueueMutationsRef]);

  const handleToggleWatchlist = useCallback(async (participantId: string) => {
    if (!userTeam) return;

    setWatchedParticipantIds((prev) => {
      const next = new Set(prev);
      if (next.has(participantId)) {
        next.delete(participantId);
      } else {
        next.add(participantId);
      }
      return next;
    });

    const formData = new FormData();
    formData.append("seasonId", season.id);
    formData.append("teamId", userTeam.id);
    formData.append("participantId", participantId);

    try {
      const response = await authFetch("/api/watchlist/toggle", {
        method: "POST",
        body: formData,
      });
      if (!response) {
        setWatchedParticipantIds((prev) => {
          const next = new Set(prev);
          if (next.has(participantId)) { next.delete(participantId); } else { next.add(participantId); }
          return next;
        });
        return;
      }
      if (!response.ok) {
        setWatchedParticipantIds((prev) => {
          const next = new Set(prev);
          if (next.has(participantId)) { next.delete(participantId); } else { next.add(participantId); }
          return next;
        });
        const error = await response.json();
        toast.error(error.error || "Failed to update watchlist");
      }
    } catch {
      setWatchedParticipantIds((prev) => {
        const next = new Set(prev);
        if (next.has(participantId)) { next.delete(participantId); } else { next.add(participantId); }
        return next;
      });
      toast.error("Network error - failed to update watchlist");
    }
  }, [userTeam, season.id, authFetch, setWatchedParticipantIds]);

  const handleStartDraft = async () => {
    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);

      const response = await authFetch("/api/draft/start", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        revalidate();
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to start draft");
      }
    } catch {
      toast.error("Network error - failed to start draft");
    }
  };

  const handlePauseDraft = async () => {
    const formData = new FormData();
    formData.append("seasonId", season.id);

    try {
      const response = await authFetch("/api/draft/pause", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        setIsPaused(true);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to pause draft");
      }
    } catch {
      toast.error("Network error - failed to pause draft");
    }
  };

  const handleResumeDraft = async () => {
    const formData = new FormData();
    formData.append("seasonId", season.id);

    try {
      const response = await authFetch("/api/draft/resume", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        setIsPaused(false);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to resume draft");
      }
    } catch {
      toast.error("Network error - failed to resume draft");
    }
  };

  const handleMakePick = useCallback(async (participantId: string) => {
    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("participantId", participantId);

      const response = await authFetch("/api/draft/make-pick", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (!response.ok) {
        const error = await response.json();
        toast.error(error.error || "Failed to make pick");
      }
    } catch {
      toast.error("Network error - failed to make pick");
    }
  }, [season.id, authFetch]);

  const handleForceAutopick = useCallback(async (pickNumber: number, teamId: string) => {
    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("teamId", teamId);
      formData.append("pickNumber", pickNumber.toString());

      const response = await authFetch("/api/draft/force-autopick", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (!response.ok) {
        const error = await response.json();
        toast.error(error.error || "Failed to force autopick");
      }
    } catch {
      toast.error("Network error - failed to force autopick");
    }
  }, [season.id, authFetch]);

  const handleForceManualPick = async (participantId: string) => {
    if (!selectedPickSlot) return;

    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("teamId", selectedPickSlot.teamId);
      formData.append("participantId", participantId);
      formData.append("pickNumber", selectedPickSlot.pickNumber.toString());

      const response = await authFetch("/api/draft/force-manual-pick", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        setForcePickDialogOpen(false);
        setSelectedPickSlot(null);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to force manual pick");
      }
    } catch {
      toast.error("Network error - failed to force manual pick");
    }
  };

  const handleReplacePickOpen = useCallback((pickNumber: number, teamId: string) => {
    const pick = picks.find((p) => p.pickNumber === pickNumber);
    if (!pick) {
      toast.error("Pick not found — try refreshing the page");
      return;
    }
    setReplacePickSlot({ pickNumber, teamId, oldParticipantId: pick.participant.id });
    setReplacePickDialogOpen(true);
  // picks is read directly to find the pick being replaced.
  }, [picks, setReplacePickSlot, setReplacePickDialogOpen]);

  const handleReplacePick = async (participantId: string) => {
    if (!replacePickSlot) return;

    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("teamId", replacePickSlot.teamId);
      formData.append("participantId", participantId);
      formData.append("pickNumber", replacePickSlot.pickNumber.toString());

      const response = await authFetch("/api/draft/replace-pick", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        setReplacePickDialogOpen(false);
        setReplacePickSlot(null);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to replace pick");
      }
    } catch {
      toast.error("Network error - failed to replace pick");
    }
  };

  const handleRollbackToPick = useCallback((pickNumber: number) => {
    setRollbackPickNumber(pickNumber);
    setRollbackConfirmOpen(true);
  }, [setRollbackPickNumber, setRollbackConfirmOpen]);

  const handleConfirmRollback = async () => {
    if (!rollbackPickNumber || isRollingBack) return;

    setIsRollingBack(true);
    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("pickNumber", rollbackPickNumber.toString());

      const response = await authFetch("/api/draft/rollback", {
        method: "POST",
        body: formData,
      });

      setIsRollingBack(false);
      if (!response) return;

      if (response.ok) {
        setRollbackConfirmOpen(false);
        setRollbackPickNumber(null);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to roll back draft");
      }
    } catch {
      setIsRollingBack(false);
      toast.error("Network error - failed to roll back draft");
    }
  };

  const handleAdjustTimeBankOpen = useCallback((teamId: string) => {
    setTimeBankTeamId(teamId);
    setTimeBankAmount("1");
    setTimeBankUnit("minutes");
    setTimeBankDirection("add");
    setTimeBankDialogOpen(true);
  }, [setTimeBankTeamId, setTimeBankAmount, setTimeBankUnit, setTimeBankDirection, setTimeBankDialogOpen]);

  const handleSetAutodraftOpen = useCallback((teamId: string) => {
    setCommissionerAutodraftTeamId(teamId);
    setCommissionerAutodraftDialogOpen(true);
  }, [setCommissionerAutodraftTeamId, setCommissionerAutodraftDialogOpen]);

  const handleCommissionerAutodraftUpdate = useCallback(() => {
    setCommissionerAutodraftDialogOpen(false);
    setCommissionerAutodraftTeamId(null);
  }, [setCommissionerAutodraftDialogOpen, setCommissionerAutodraftTeamId]);

  const handleConfirmAdjustTimeBank = async () => {
    if (!timeBankTeamId || isAdjustingTimeBank) return;

    const amount = parseFloat(timeBankAmount);
    if (isNaN(amount) || amount <= 0) {
      toast.error("Please enter a valid positive amount");
      return;
    }

    const unitMultipliers = { seconds: 1, minutes: 60, hours: 3600 };
    const totalSeconds = Math.round(amount * unitMultipliers[timeBankUnit]);

    if (totalSeconds === 0) {
      toast.error("Adjustment rounds to 0 seconds — please enter a larger value");
      return;
    }

    const adjustment = timeBankDirection === "add" ? totalSeconds : -totalSeconds;

    setIsAdjustingTimeBank(true);
    try {
      const formData = new FormData();
      formData.append("seasonId", season.id);
      formData.append("teamId", timeBankTeamId);
      formData.append("adjustment", adjustment.toString());

      const response = await authFetch("/api/draft/adjust-time-bank", {
        method: "POST",
        body: formData,
      });
      if (!response) return;

      if (response.ok) {
        const data = await response.json();
        setTeamTimers((prev) => ({ ...prev, [timeBankTeamId]: data.timeRemaining }));
        const teamName = draftSlots.find((s) => s.team.id === timeBankTeamId)?.team.name;
        toast.success(`Time bank adjusted for ${teamName}`);
        setTimeBankDialogOpen(false);
        setTimeBankTeamId(null);
      } else {
        const error = await response.json();
        toast.error(error.error || "Failed to adjust time bank");
      }
    } catch {
      toast.error("Network error — failed to adjust time bank");
    } finally {
      setIsAdjustingTimeBank(false);
    }
  };

  const handleForceManualPickOpen = useCallback((pickNumber: number, teamId: string) => {
    setSelectedPickSlot({ pickNumber, teamId });
    setForcePickDialogOpen(true);
  }, [setSelectedPickSlot, setForcePickDialogOpen]);

  // Calculate current round
  const currentRound = draftSlots.length > 0 ? Math.ceil(currentPick / draftSlots.length) : 1;

  // Determine whose turn it is
  const currentDraftSlot = useMemo(
    () => getTeamForPick(currentPick, draftSlots),
    [currentPick, draftSlots]
  );
  const isMyTurn = !!(
    userTeam && currentDraftSlot && currentDraftSlot.team.id === userTeam.id
  );
  const canPick = isMyTurn && season.status === "draft" && !isPaused; // Only team owner on their turn when draft is active

  const currentDraftSlotOwnerName = currentDraftSlot ? ownerMap[currentDraftSlot.team.id] : undefined;
  const currentClockTime = currentDraftSlot ? teamTimers[currentDraftSlot.team.id] : undefined;
  const currentClockColor = getTimerColorClass(currentClockTime);

  // Generate snake draft grid structure
  const draftGrid = useMemo(() => {
    const teamCount = draftSlots.length;
    const rounds = season.draftRounds;
    const pickMap = new Map(picks.map((p) => [p.pickNumber, p]));
    const grid: Array<
      Array<{
        pickNumber: number;
        round: number;
        pickInRound: number;
        teamId: string;
        pick?: (typeof draftPicks)[number];
      }>
    > = [];

    for (let round = 1; round <= rounds; round++) {
      const roundPicks = [];
      const isOddRound = round % 2 === 1;

      for (let i = 0; i < teamCount; i++) {
        const pickInRound = i + 1;
        const teamIndex = isOddRound ? i : teamCount - 1 - i;
        const pickNumber = (round - 1) * teamCount + pickInRound;
        const teamId = draftSlots[teamIndex]?.team.id;

        const pick = pickMap.get(pickNumber);

        roundPicks.push({ pickNumber, round, pickInRound, teamId, pick });
      }
      grid.push(roundPicks);
    }

    return grid;
  }, [picks, draftSlots, season.draftRounds]);

  const projectedPicks = useMemo(() => {
    if (!userTeam || season.status !== "draft" || isDraftComplete) return [];
    return getProjectedPicks({
      draftSlots,
      userTeamId: userTeam.id,
      currentPick,
      totalRounds: season.draftRounds,
      existingPicks: picks.map((p) => ({
        pickNumber: p.pickNumber,
        teamId: p.team.id,
      })),
    });
  }, [userTeam, season.status, isDraftComplete, draftSlots, currentPick, season.draftRounds, picks]);

  // Get drafted participant IDs for filtering
  const draftedParticipantIds = useMemo(
    () => new Set(picks.map((p) => p.participant.id)),
    [picks]
  );

  // Sport IDs where the current user's team has already made at least one pick
  const userDraftedSportIds = useMemo(() => {
    if (!userTeam) return new Set<string>();
    return new Set(
      picks
        .filter((p) => p.team.id === userTeam.id)
        .map((p) => p.sport.id)
    );
  }, [picks, userTeam]);

  // Sport names where the current user's team has already made at least one pick
  const userDraftedSportNames = useMemo(() => {
    if (!userTeam) return new Set<string>();
    return new Set(
      picks
        .filter((p) => p.team.id === userTeam.id)
        .map((p) => p.sport.name)
    );
  }, [picks, userTeam]);

  // Get unique sports for filter dropdown
  const uniqueSports = useMemo(
    () =>
      Array.from(
        new Set(availableParticipants.map((p) => p.sport.name))
      ).sort(),
    [availableParticipants]
  );

  // Filter participants based on search, sport, drafted status, and eligibility
  const filteredParticipants = useMemo(() => {
    const sportFilterSet = new Set(sportFilters);
    return sortedAvailableParticipants.filter((participant) => {
      // Drafted filter - hide drafted participants by default, but keep animating-out rows visible
      if (hideDrafted && draftedParticipantIds.has(participant.id) && !animatingOutParticipantIds.has(participant.id)) {
        return false;
      }
      // Eligibility filter - hide ineligible participants by default (if user has a team)
      if (hideIneligible && eligibility) {
        const isEligible = eligibility.eligibleSportIds.has(participant.sport.id);
        if (!isEligible) {
          return false;
        }
      }
      // Hide completed sports filter - hide participants from sports already drafted by user's team
      if (hideCompletedSports && userDraftedSportIds.has(participant.sport.id)) {
        return false;
      }
      // Search filter
      if (
        searchQuery &&
        !participant.name.toLowerCase().includes(searchQuery.toLowerCase())
      ) {
        return false;
      }
      // Sport filter
      if (sportFilterSet.size > 0 && !sportFilterSet.has(participant.sport.name)) {
        return false;
      }
      // Watched only filter
      if (showOnlyWatched && !watchedParticipantIds.has(participant.id)) {
        return false;
      }
      return true;
    });
  }, [sortedAvailableParticipants, hideDrafted, hideIneligible, hideCompletedSports, eligibility, draftedParticipantIds, animatingOutParticipantIds, userDraftedSportIds, searchQuery, sportFilters, showOnlyWatched, watchedParticipantIds]);

  // Shared component props — defined once to avoid duplication between desktop and mobile layouts
  const handleHideCompletedSportsChange = useCallback((hide: boolean) => {
    setHideCompletedSports(hide);
    if (hide) {
      setSportFilters((prev) => prev.filter((s) => !userDraftedSportNames.has(s)));
    }
  }, [userDraftedSportNames, setHideCompletedSports, setSportFilters]);

  const miniDraftGrid = useMemo(() => ({
    draftSlots,
    draftGrid,
    currentPick,
    currentRound,
    ownerMap,
    teamTimers,
    autodraftStatus,
    connectedTeams,
    seasonStatus: season.status,
    draftPaused: isPaused,
    overnightPauseInfo: { isActive: isOvernightPause, resumesAt: overnightResumesAt, pausedTeamIds },
    onAdjustTimeBankOpen: isCommissioner ? handleAdjustTimeBankOpen : undefined,
    onSetAutodraftOpen: isCommissioner ? handleSetAutodraftOpen : undefined,
    onForceAutopick: isCommissioner ? handleForceAutopick : undefined,
    onForceManualPickOpen: isCommissioner ? handleForceManualPickOpen : undefined,
    onReplacePick: isCommissioner ? handleReplacePickOpen : undefined,
    onRollbackToPick: isCommissioner && !isDraftComplete ? handleRollbackToPick : undefined,
  }), [draftSlots, draftGrid, currentPick, currentRound, ownerMap, teamTimers, autodraftStatus, connectedTeams, season.status, isPaused, isOvernightPause, overnightResumesAt, pausedTeamIds, isCommissioner, handleAdjustTimeBankOpen, handleSetAutodraftOpen, handleForceAutopick, handleForceManualPickOpen, handleReplacePickOpen, handleRollbackToPick, isDraftComplete]);

  const availableParticipantsSectionProps = useMemo(() => ({
    participants: filteredParticipants,
    participantRanks,
    miniDraftGrid,
    searchQuery,
    sportFilters,
    hideDrafted,
    hideIneligible,
    uniqueSports,
    draftedParticipantIds,
    queue,
    eligibility,
    canPick,
    hasTeam: !!userTeam,
    onSearchChange: setSearchQuery,
    onSportFiltersChange: setSportFilters,
    onHideDraftedChange: setHideDrafted,
    onHideIneligibleChange: setHideIneligible,
    hideCompletedSports,
    userDraftedSportNames,
    onHideCompletedSportsChange: handleHideCompletedSportsChange,
    onMakePick: handleMakePick,
    onAddToQueue: handleAddToQueue,
    onRemoveFromQueue: handleRemoveFromQueue,
    projectedPicks,
    watchedParticipantIds,
    onToggleWatchlist: handleToggleWatchlist,
    showOnlyWatched,
    onShowOnlyWatchedChange: setShowOnlyWatched,
    pickAnimationSignal,
  }), [filteredParticipants, participantRanks, miniDraftGrid, searchQuery, sportFilters, hideDrafted, hideIneligible, uniqueSports, draftedParticipantIds, queue, eligibility, canPick, userTeam, hideCompletedSports, userDraftedSportNames, handleHideCompletedSportsChange, handleMakePick, handleAddToQueue, handleRemoveFromQueue, setSearchQuery, setSportFilters, setHideDrafted, setHideIneligible, projectedPicks, watchedParticipantIds, handleToggleWatchlist, showOnlyWatched, setShowOnlyWatched, pickAnimationSignal]);

  const draftGridSectionProps = {
    draftSlots,
    draftGrid,
    currentPick,
    teamTimers,
    autodraftStatus,
    connectedTeams,
    isCommissioner,
    ownerMap,
    seasonStatus: season.status,
    draftPaused: isPaused,
    overnightPauseInfo: { isActive: isOvernightPause, resumesAt: overnightResumesAt, pausedTeamIds },
    onAdjustTimeBankOpen: isCommissioner ? handleAdjustTimeBankOpen : undefined,
    onSetAutodraftOpen: isCommissioner ? handleSetAutodraftOpen : undefined,
    onForceAutopick: isCommissioner ? handleForceAutopick : undefined,
    onForceManualPickOpen: isCommissioner ? handleForceManualPickOpen : undefined,
    onReplacePick: isCommissioner ? handleReplacePickOpen : undefined,
    onRollbackToPick: isCommissioner && !isDraftComplete ? handleRollbackToPick : undefined,
  };

  const summaryViewProps = {
    draftSlots,
    picks,
    sports: seasonSportsData,
    ownerMap,
    totalRounds: season.draftRounds,
  };

  const rosterViewProps = {
    draftSlots,
    picks,
    sports: seasonSportsData,
    ownerMap,
    totalRounds: season.draftRounds,
  };

  const handleAutodraftUpdate = useCallback(
    (isEnabled: boolean, mode: "next_pick" | "while_on", queueOnly: boolean) => {
      setUserAutodraft({ isEnabled, mode, queueOnly });
    },
    [setUserAutodraft]
  );

  const queueSectionProps = userTeam
    ? {
        queue,
        availableParticipants: sortedAvailableParticipants,
        canPick,
        onRemoveFromQueue: handleRemoveFromQueue,
        onReorder: handleReorderQueue,
        onMakePick: handleMakePick,
      }
    : null;

  const mobileTabs = userTeam
    ? [MOBILE_TABS_BASE[0], QUEUE_TAB, ...MOBILE_TABS_BASE.slice(1)]
    : MOBILE_TABS_BASE;
  const mobileColCount = mobileTabs.length;

  return (
    <div className="h-dvh bg-background flex flex-col overflow-hidden">
      {/* Draft Completion Banner */}
      {isDraftComplete && (
        <div className="bg-emerald-500/20 border-b border-emerald-500/30 text-emerald-400 px-4 py-3 text-center font-semibold flex-shrink-0 flex items-center justify-center gap-2 flex-wrap">
          <span>Draft Complete! The season is now active.</span>
          <a
            href={draftBoardUrl}
            className="inline-flex items-center gap-1 bg-emerald-500/30 hover:bg-emerald-500/40 text-emerald-300 px-3 py-1 rounded-md text-sm transition-colors"
          >
            View Draft Board
          </a>
          {roomClosureCountdown !== null && roomClosureCountdown > 0 && (
            <span aria-live="polite" aria-atomic="true" className="text-sm text-emerald-500">
              Room closes in {Math.floor(roomClosureCountdown / 60)}:{String(roomClosureCountdown % 60).padStart(2, "0")}
            </span>
          )}
        </div>
      )}

      {/* Standalone Header - No Main Nav */}
      <div className="border-b bg-card flex-shrink-0">
        <div className="w-full px-4 py-4">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              {/* Mobile menu button - only show if user has team and sidebar is collapsed */}
              {userTeam && sidebarCollapsed && (
                <Button
                  variant="ghost"
                  size="icon"
                  onClick={() => setSidebarCollapsed(false)}
                  className="lg:hidden"
                  aria-label="Open sidebar"
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    width="24"
                    height="24"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <line x1="3" y1="12" x2="21" y2="12" />
                    <line x1="3" y1="6" x2="21" y2="6" />
                    <line x1="3" y1="18" x2="21" y2="18" />
                  </svg>
                </Button>
              )}
              <Link to="/">
                <img src={logomarkUrl} alt="Brackt" className="h-8" />
              </Link>
              <h1 className="text-lg md:text-xl font-bold">
                Draft Room
              </h1>
            </div>
            <div className="flex items-center gap-3">
              <div className="hidden md:flex items-center gap-2 relative">
                <span className="text-xs text-muted-foreground">Push Notifications</span>
                <NotificationSettings
                  enabled={notificationsEnabled}
                  onEnabledChange={setNotificationsEnabled}
                  mode={notificationsMode}
                  onModeChange={setNotificationsMode}
                  permissionState={notificationsPermission}
                  switchOnly
                />
              </div>
              {/* Commissioner Controls - hidden on mobile (shown in Controls tab) */}
              {isCommissioner && (
                <div className="hidden md:flex">
                  <CommissionerDraftControls
                    seasonStatus={season.status}
                    isDraftComplete={isDraftComplete}
                    isPaused={isPaused}
                    onStart={handleStartDraft}
                    onPause={handlePauseDraft}
                    onResume={handleResumeDraft}
                    autoStartDraft={season.autoStartDraft}
                    secondsUntilAutoStart={secondsUntilAutoStart}
                  />
                </div>
              )}

              <Button variant="outline" asChild className="hidden md:flex">
                <Link to={`/leagues/${season.leagueId}`}>Exit Draft Room</Link>
              </Button>
            </div>
          </div>
        </div>
      </div>

      {/* Mobile On Clock bar */}
      {season.status === "draft" && !isDraftComplete && currentDraftSlot && (
        <div aria-live="assertive" aria-atomic="true" className={`md:hidden flex-shrink-0 flex items-center justify-between px-4 py-2 border-b ${
          isMyTurn
            ? isOvernightPause
              ? "bg-blue-950/40 border-blue-800/40"
              : "bg-electric/25 border-electric"
            : "bg-muted/30"
        }`}>
          <div>
            <div className={`text-xs font-bold uppercase tracking-wider ${
              isMyTurn
                ? isOvernightPause ? "text-blue-400" : "text-electric"
                : "text-muted-foreground"
            }`}>
              {isMyTurn
                ? isOvernightPause ? "Overnight Pause" : "Your Turn!"
                : "On the Clock"}
            </div>
            <div className="text-sm font-bold">
              {currentDraftSlotOwnerName ?? currentDraftSlot.team.name}
            </div>
            {currentDraftSlotOwnerName && (
              <div className="text-xs text-muted-foreground">{currentDraftSlot.team.name}</div>
            )}
          </div>
          {isPaused ? (
            <span className="text-sm font-bold text-amber-accent">Paused</span>
          ) : isOvernightPause ? (
            <span className={`text-xl font-mono font-bold tabular-nums ${currentClockColor}`}>
              🌙 {formatClockTime(currentClockTime)}
            </span>
          ) : (
            <span className={`text-xl font-mono font-bold tabular-nums ${currentClockColor}`}>
              {formatClockTime(currentClockTime)}
            </span>
          )}
        </div>
      )}

      {/* Desktop Tab Navigation Row */}
      <div className={`hidden md:grid md:grid-cols-3 flex-shrink-0 items-center px-4 py-2 border-b transition-all duration-300 ${
        isMyTurn && season.status === "draft" && !isDraftComplete
          ? isOvernightPause
            ? "bg-blue-950/40 border-blue-800/40"
            : "bg-electric/25 border-electric shadow-[0_0_24px_0_rgb(0_200_255_/_0.18)]"
          : "bg-card"
      }`}>
        <Tabs
          value={activeTab}
          onValueChange={(value) =>
            setActiveTab(value as "participants" | "board" | "rosters" | "summary")
          }
        >
          <TabsList>
            <TabsTrigger value="participants">Participants</TabsTrigger>
            <TabsTrigger value="board">Draft Board</TabsTrigger>
            <TabsTrigger value="rosters">Rosters</TabsTrigger>
            <TabsTrigger value="summary">Summary</TabsTrigger>
          </TabsList>
        </Tabs>
        <div className="flex justify-center" aria-live="assertive" aria-atomic="true">
          {isMyTurn && season.status === "draft" && !isDraftComplete && (
            isOvernightPause ? (
              <span className="text-sm text-blue-200 text-center leading-snug">
                🌙 Overnight pause active — timer frozen
                {overnightResumesAt && (
                  <> until {overnightResumesAt.toLocaleTimeString(undefined, { hour: "numeric", minute: "2-digit" })}</>
                )}. You can still pick.
              </span>
            ) : (
              <span className="text-base font-bold tracking-wide text-electric">
                It&apos;s your turn!
              </span>
            )
          )}
        </div>
        <div className="flex justify-end">
          {userTeam && (
            <AutodraftBadgeWithPopover
              seasonId={season.id}
              teamId={userTeam.id}
              isEnabled={userAutodraft.isEnabled}
              mode={userAutodraft.mode}
              queueOnly={userAutodraft.queueOnly}
              isMyTurn={isMyTurn}
              onUpdate={handleAutodraftUpdate}
              showOvernightNote={season.overnightPauseMode !== "none"}
            />
          )}
        </div>
      </div>

      {/* Main Content — single layout tree based on isMobile to avoid duplicate component instances */}
      <div className="flex-1 overflow-hidden">
        {isMobile ? (
          <div className="flex h-full overflow-hidden flex-col">
            {mobileTab === "available" && (
              <div className="flex flex-col h-full overflow-hidden">
                <div className="flex-shrink-0">
                  <RecentPicksFeed picks={picks} />
                </div>
                <div className="flex-1 min-h-0 overflow-hidden">
                  <AvailableParticipantsSection {...availableParticipantsSectionProps} miniDraftGrid={undefined} />
                </div>
              </div>
            )}
            {mobileTab === "queue" && (
              <div className="h-full overflow-y-auto">
                {queueSectionProps ? (
                  <QueueSection {...queueSectionProps} />
                ) : (
                  <p className="text-muted-foreground text-sm text-center py-8 px-4">
                    Join a team to manage your queue
                  </p>
                )}
              </div>
            )}
            {mobileTab === "board" && (
              <div className="flex flex-col h-full overflow-hidden">
                <div role="tablist" aria-label="Board view" className="flex-shrink-0 flex gap-1 p-2 border-b">
                  <button
                    role="tab"
                    aria-selected={boardSubTab === "board"}
                    aria-controls="board-subtab-panel"
                    onClick={() => setBoardSubTab("board")}
                    className={`flex-1 py-1.5 text-sm font-medium rounded transition-colors ${
                      boardSubTab === "board"
                        ? "bg-accent text-accent-foreground"
                        : "text-muted-foreground hover:text-foreground"
                    }`}
                  >
                    Board
                  </button>
                  <button
                    role="tab"
                    aria-selected={boardSubTab === "pick-list"}
                    aria-controls="board-subtab-panel"
                    onClick={() => setBoardSubTab("pick-list")}
                    className={`flex-1 py-1.5 text-sm font-medium rounded transition-colors ${
                      boardSubTab === "pick-list"
                        ? "bg-accent text-accent-foreground"
                        : "text-muted-foreground hover:text-foreground"
                    }`}
                  >
                    Pick List
                  </button>
                </div>
                <div id="board-subtab-panel" role="tabpanel" className="flex-1 overflow-hidden">
                  {boardSubTab !== "pick-list" ? (
                    <DraftGridSection {...draftGridSectionProps} />
                  ) : (
                    <div className="h-full overflow-y-auto p-4">
                      <SidebarRecentPicks picks={picks} />
                    </div>
                  )}
                </div>
              </div>
            )}
            {mobileTab === "teams" && (
              <div className="flex flex-col h-full overflow-hidden">
                <div className="flex-shrink-0 flex gap-1 p-2 border-b">
                  <button
                    onClick={() => setTeamsSubTab("rosters")}
                    className={`flex-1 py-1.5 text-sm font-medium rounded transition-colors ${
                      teamsSubTab === "rosters"
                        ? "bg-accent text-accent-foreground"
                        : "text-muted-foreground hover:text-foreground"
                    }`}
                  >
                    Roster
                  </button>
                  <button
                    onClick={() => setTeamsSubTab("summary")}
                    className={`flex-1 py-1.5 text-sm font-medium rounded transition-colors ${
                      teamsSubTab === "summary"
                        ? "bg-accent text-accent-foreground"
                        : "text-muted-foreground hover:text-foreground"
                    }`}
                  >
                    Summary
                  </button>
                </div>
                <div className="flex-1 overflow-hidden">
                  {teamsSubTab === "rosters" ? (
                    <TeamRosterView {...rosterViewProps} />
                  ) : (
                    <DraftSummaryView {...summaryViewProps} />
                  )}
                </div>
              </div>
            )}
            {mobileTab === "controls" && (
              <div className="h-full flex flex-col">
                <div className="flex-1 overflow-y-auto p-4">
                  {isCommissioner && season.status === "pre_draft" && (
                    <CommissionerDraftControls
                      seasonStatus={season.status}
                      isDraftComplete={isDraftComplete}
                      isPaused={isPaused}
                      onStart={handleStartDraft}
                      onPause={handlePauseDraft}
                      onResume={handleResumeDraft}
                      buttonClassName="w-full min-h-[48px]"
                      autoStartDraft={season.autoStartDraft}
                      secondsUntilAutoStart={secondsUntilAutoStart}
                    />
                  )}

                  {userTeam && (
                    <AutodraftSettings
                      seasonId={season.id}
                      teamId={userTeam.id}
                      isEnabled={userAutodraft.isEnabled}
                      mode={userAutodraft.mode}
                      queueOnly={userAutodraft.queueOnly}
                      isMyTurn={isMyTurn}
                      onUpdate={handleAutodraftUpdate}
                      showOvernightNote={season.overnightPauseMode !== "none"}
                    />
                  )}
                </div>

                <div className="flex-shrink-0 p-4 border-t flex flex-col gap-3">
                  {isCommissioner && season.status === "draft" && !isDraftComplete && (
                    isPaused ? (
                      <Button className="w-full min-h-[48px]" onClick={handleResumeDraft}>
                        Resume Draft
                      </Button>
                    ) : (
                      <Button className="w-full min-h-[48px]" variant="outline" onClick={handlePauseDraft}>
                        Pause Draft
                      </Button>
                    )
                  )}
                  <Button variant="outline" asChild className="w-full min-h-[48px]">
                    <Link to={`/leagues/${season.leagueId}`}>Exit Draft Room</Link>
                  </Button>
                </div>
              </div>
            )}
          </div>
        ) : (
          <div className="flex h-full overflow-hidden">
            {userTeam && queueSectionProps && (
              <DraftSidebar
                collapsed={sidebarCollapsed}
                onCollapsedChange={setSidebarCollapsed}
                queueSection={<QueueSection {...queueSectionProps} />}
                recentPicksSection={<SidebarRecentPicks picks={picks} />}
              />
            )}

            <div className="flex-1 overflow-hidden relative">
              <div className={`absolute inset-0 ${activeTab === "participants" ? "" : "hidden"}`}>
                <AvailableParticipantsSection {...availableParticipantsSectionProps} />
              </div>
              <div className={`absolute inset-0 ${activeTab === "board" ? "" : "hidden"}`}>
                <DraftGridSection {...draftGridSectionProps} />
              </div>
              <div className={`absolute inset-0 ${activeTab === "rosters" ? "" : "hidden"}`}>
                <TeamRosterView {...rosterViewProps} />
              </div>
              <div className={`absolute inset-0 ${activeTab === "summary" ? "" : "hidden"}`}>
                <DraftSummaryView {...summaryViewProps} />
              </div>
            </div>
          </div>
        )}
      </div>

      {/* Mobile Bottom Nav */}
      <nav className={`md:hidden flex-shrink-0 border-t bg-card grid`} style={{ gridTemplateColumns: `repeat(${mobileColCount}, 1fr)` }}>
        {mobileTabs.map((tab) => {
          const showTurnIndicator =
            (tab.id === "available" || tab.id === "queue") &&
            isMyTurn &&
            season.status === "draft" &&
            !isDraftComplete;
          return (
            <button
              key={tab.id}
              onClick={() => setMobileTab(tab.id as typeof mobileTab)}
              className={`relative flex flex-col items-center justify-center py-2 gap-0.5 min-h-[56px] transition-colors ${
                mobileTab === tab.id ? "text-electric" : "text-muted-foreground"
              }`}
            >
              <div className="relative">
                <tab.Icon className="h-5 w-5" />
                {showTurnIndicator && (
                  <span className="absolute -top-1 -right-1 w-2 h-2 rounded-full bg-electric" />
                )}
              </div>
              <span className="text-[10px] font-medium">{tab.label}</span>
            </button>
          );
        })}
      </nav>

      <ParticipantSelectionDialog
        open={forcePickDialogOpen && !!selectedPickSlot}
        onOpenChange={(open) => {
          setForcePickDialogOpen(open);
          if (!open) setSelectedPickSlot(null);
        }}
        title="Force Manual Pick"
        description={`Select a participant to draft for Pick #${selectedPickSlot?.pickNumber}`}
        participants={sortedAvailableParticipants}
        draftedParticipantIds={draftedParticipantIds}
        eligibility={forcePickEligibility}
        uniqueSports={uniqueSports}
        onSelect={handleForceManualPick}
      />

      <ParticipantSelectionDialog
        open={replacePickDialogOpen && !!replacePickSlot}
        onOpenChange={(open) => {
          setReplacePickDialogOpen(open);
          if (!open) setReplacePickSlot(null);
        }}
        title="Replace Pick"
        description={`Select a participant to replace the current pick at slot #${replacePickSlot?.pickNumber}`}
        participants={sortedAvailableParticipants}
        draftedParticipantIds={draftedParticipantIds}
        allowParticipantId={replacePickSlot?.oldParticipantId}
        currentParticipantId={replacePickSlot?.oldParticipantId}
        eligibility={replacePickEligibility}
        uniqueSports={uniqueSports}
        onSelect={handleReplacePick}
      />


      {/* Rollback Confirmation Dialog */}
      <RollbackConfirmDialog
        open={rollbackConfirmOpen}
        onOpenChange={(open) => { setRollbackConfirmOpen(open); if (!open) setRollbackPickNumber(null); }}
        pickNumber={rollbackPickNumber}
        picksCount={rollbackPickNumber !== null ? picks.filter((p) => p.pickNumber >= rollbackPickNumber).length : 0}
        isRollingBack={isRollingBack}
        onConfirm={handleConfirmRollback}
      />

      {/* Time Bank Adjustment Dialog */}
      <TimeBankAdjustmentDialog
        open={timeBankDialogOpen}
        onOpenChange={(open) => { setTimeBankDialogOpen(open); if (!open) setTimeBankTeamId(null); }}
        teamName={draftSlots.find((s) => s.team.id === timeBankTeamId)?.team.name}
        amount={timeBankAmount}
        onAmountChange={setTimeBankAmount}
        unit={timeBankUnit}
        onUnitChange={setTimeBankUnit}
        direction={timeBankDirection}
        onDirectionChange={setTimeBankDirection}
        isAdjusting={isAdjustingTimeBank}
        onConfirm={handleConfirmAdjustTimeBank}
      />

      {/* Commissioner Autodraft Override Dialog */}
      <CommissionerAutodraftDialog
        open={commissionerAutodraftDialogOpen}
        onOpenChange={(open) => { setCommissionerAutodraftDialogOpen(open); if (!open) setCommissionerAutodraftTeamId(null); }}
        teamId={commissionerAutodraftTeamId}
        teamName={draftSlots.find((s) => s.team.id === commissionerAutodraftTeamId)?.team.name}
        seasonId={season.id}
        isEnabled={autodraftStatus[commissionerAutodraftTeamId ?? ""]?.isEnabled ?? false}
        mode={autodraftStatus[commissionerAutodraftTeamId ?? ""]?.mode ?? "next_pick"}
        queueOnly={autodraftStatus[commissionerAutodraftTeamId ?? ""]?.queueOnly ?? false}
        onUpdate={handleCommissionerAutodraftUpdate}
      />

      {/* Connection Overlay - blocks interaction until socket connects */}
      <ConnectionOverlay
        isConnected={isConnected}
        isReconnecting={isReconnecting}
        connectionError={connectionError}
        isSyncing={isSyncing}
      />

      {/* Auth Recovery Overlay - blocks interaction when session expires */}
      <AuthRecoveryOverlay isAuthDegraded={authDegraded} />
    </div>
  );
}
