import { useLoaderData, Link, useRevalidator } from "react-router";
import { useAuth } from "@clerk/react-router";
import { eq, and, asc, desc, inArray } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { useDraftSocket } from "~/hooks/useDraftSocket";
import { useEffect, useState, useMemo, useRef } from "react";
import { Card } from "~/components/ui/card";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "~/components/ui/dialog";
import { getAuth } from "@clerk/react-router/server";
import { getTeamQueue } from "~/models/draft-queue";
import { buildOwnerMap } from "~/lib/owner-map";
import { DraftSidebar } from "~/components/DraftSidebar";
import { TeamsDraftedGrid } from "~/components/draft/TeamsDraftedGrid";
import { QueueSection } from "~/components/draft/QueueSection";
import { AvailableParticipantsSection } from "~/components/draft/AvailableParticipantsSection";
import { SidebarRecentPicks } from "~/components/draft/SidebarRecentPicks";
import { DraftGridSection } from "~/components/draft/DraftGridSection";
import { ConnectionOverlay } from "~/components/draft/ConnectionOverlay";
import { ParticipantSelectionDialog } from "~/components/draft/ParticipantSelectionDialog";
import { calculateDraftEligibility } from "~/lib/draft-eligibility";
import { getTeamForPick } from "~/lib/draft-order";
import { useDraftNotifications } from "~/hooks/useDraftNotifications";
import { useMediaQuery } from "~/hooks/useMediaQuery";
import { NotificationSettings } from "~/components/NotificationSettings";
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";

type QueueItem = typeof schema.draftQueue.$inferSelect;

const MOBILE_TABS_BASE = [
  { id: "available" as const, label: "Available", Icon: Users },
  { id: "board" as const, label: "Board", Icon: LayoutGrid },
  { id: "roster" as const, label: "Roster", 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 { userId } = await getAuth(args);

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

  const db = database();

  // Get season details
  const season = await db.query.seasons.findFirst({
    where: eq(schema.seasons.id, seasonId),
    with: {
      league: true,
      teams: true,
    },
  });

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

  // Resolve user's team and commissioner status (null userId means neither)
  const userTeam = userId
    ? season.teams.find((team: any) => team.ownerId === userId)
    : undefined;

  const isCommissioner = userId
    ? await db.query.commissioners.findFirst({
        where: and(
          eq(schema.commissioners.leagueId, leagueId),
          eq(schema.commissioners.userId, userId)
        ),
      })
    : null;

  // Access control: if draft board is not public, require authentication and membership
  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,
      });
    }
  }

  // Get draft slots (draft order) - using select instead of query builder
  const draftSlots = await db
    .select({
      id: schema.draftSlots.id,
      draftOrder: schema.draftSlots.draftOrder,
      team: schema.teams,
    })
    .from(schema.draftSlots)
    .innerJoin(schema.teams, eq(schema.draftSlots.teamId, schema.teams.id))
    .where(eq(schema.draftSlots.seasonId, seasonId))
    .orderBy(asc(schema.draftSlots.draftOrder));

  // Get all draft picks - using select instead of query builder
  const draftPicks = await db
    .select({
      id: schema.draftPicks.id,
      pickNumber: schema.draftPicks.pickNumber,
      round: schema.draftPicks.round,
      pickInRound: schema.draftPicks.pickInRound,
      timeUsed: schema.draftPicks.timeUsed,
      team: schema.teams,
      participant: schema.participants,
      sport: schema.sports,
    })
    .from(schema.draftPicks)
    .innerJoin(schema.teams, eq(schema.draftPicks.teamId, schema.teams.id))
    .innerJoin(
      schema.participants,
      eq(schema.draftPicks.participantId, schema.participants.id)
    )
    .innerJoin(
      schema.sportsSeasons,
      eq(schema.participants.sportsSeasonId, schema.sportsSeasons.id)
    )
    .innerJoin(
      schema.sports,
      eq(schema.sportsSeasons.sportId, schema.sports.id)
    )
    .where(eq(schema.draftPicks.seasonId, seasonId))
    .orderBy(asc(schema.draftPicks.pickNumber));

  // Get sports seasons for this season
  const seasonSports = await db.query.seasonSports.findMany({
    where: eq(schema.seasonSports.seasonId, seasonId),
  });

  const sportsSeasonIds = seasonSports.map((ss) => ss.sportsSeasonId);

  // Get ALL participants (both drafted and undrafted) - sorted by EV desc, then name
  // Filtering will be done on the client side based on the "Show Drafted" toggle
  const availableParticipants = sportsSeasonIds.length > 0
    ? await db
        .select({
          id: schema.participants.id,
          name: schema.participants.name,
          sport: schema.sports,
        })
        .from(schema.participants)
        .innerJoin(
          schema.sportsSeasons,
          eq(schema.participants.sportsSeasonId, schema.sportsSeasons.id)
        )
        .innerJoin(
          schema.sports,
          eq(schema.sportsSeasons.sportId, schema.sports.id)
        )
        .where(
          sportsSeasonIds.length === 1
            ? eq(schema.participants.sportsSeasonId, sportsSeasonIds[0])
            : inArray(schema.participants.sportsSeasonId, sportsSeasonIds)
        )
        .orderBy(
          desc(schema.participants.expectedValue),
          asc(schema.participants.name)
        )
    : [];

  // Load user's team queue if they have a team
  const userQueue = userTeam
    ? await getTeamQueue(userTeam.id).catch((err) => {
        console.error("[DraftLoader] Failed to load queue, defaulting to empty:", err);
        return [];
      })
    : [];

  // Load draft timers for all teams
  const timers = await db.query.draftTimers.findMany({
    where: eq(schema.draftTimers.seasonId, seasonId),
  });

  // Load autodraft settings for all teams
  const autodraftSettings = await db.query.autodraftSettings.findMany({
    where: eq(schema.autodraftSettings.seasonId, seasonId),
  });

  // Derive user's autodraft settings from the already-loaded list
  const userAutodraftSettings = userTeam
    ? (autodraftSettings.find((s) => s.teamId === userTeam.id) ?? null)
    : null;

  const ownerMap = await buildOwnerMap(draftSlots);

  return {
    season,
    draftSlots,
    draftPicks,
    availableParticipants,
    userTeam,
    userQueue,
    timers,
    autodraftSettings,
    userAutodraftSettings,
    isCommissioner: !!isCommissioner,
    currentUserId: userId,
    numFlexPicks: Math.max(0, season.draftRounds - seasonSports.length),
    ownerMap,
  };
}

export default function DraftRoom() {
  const {
    season,
    draftSlots,
    draftPicks,
    availableParticipants,
    userTeam,
    userQueue,
    timers,
    autodraftSettings,
    userAutodraftSettings,
    isCommissioner,
    currentUserId,
    numFlexPicks,
    ownerMap,
  } = useLoaderData<typeof loader>();
  const { revalidate, state: revalidatorState } = useRevalidator();
  const { userId: clerkUserId } = useAuth();
  const { isConnected, connectionError, isReconnecting, reconnectCount, 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]);

  // Track current autodraft state for detecting server-initiated auto-disable
  const [userAutodraft, setUserAutodraft] = useState({
    isEnabled: userAutodraftSettings?.isEnabled || false,
    mode: (userAutodraftSettings?.mode || "next_pick") as "next_pick" | "while_on",
    queueOnly: userAutodraftSettings?.queueOnly || false,
  });
  const userAutodraftRef = useRef(userAutodraft);
  useEffect(() => {
    userAutodraftRef.current = userAutodraft;
  }, [userAutodraft]);

  // Re-fetch loader data after each reconnect so stale picks/timers are refreshed
  useEffect(() => {
    if (reconnectCount > 0) {
      revalidate();
    }
  }, [reconnectCount, revalidate]);

  // Guard against Clerk JWT expiry race: if the loader ran without a userId (expired
  // short-lived JWT) but the Clerk client SDK has a valid session, revalidate so the
  // loader re-runs with a fresh token and returns correct userTeam/userQueue data.
  useEffect(() => {
    if (clerkUserId && !currentUserId) {
      revalidate();
    }
  }, [clerkUserId, currentUserId, revalidate]);

  // Track revalidation lifecycle to sync local state from fresh loader data.
  //
  // The problem: `picks` and `currentPick` are local state initialized once
  // from useLoaderData(). When revalidate() runs after a reconnect, React
  // Router re-fetches `draftPicks`/`season` — but those updates never flow
  // back into the local useState copies automatically.
  //
  // Race condition: a `pick-made` socket event that arrives *during* the
  // revalidation window would normally be applied to the stale prev state and
  // then overwritten when we sync from the DB snapshot. We prevent that by
  // buffering live picks while revalidation is in flight and merging them
  // (deduplicated by ID) after the DB snapshot lands.
  const revalidatorStateRef = useRef(revalidatorState);
  const isRevalidatingRef = useRef(false);
  const pendingPicksDuringRevalidationRef = useRef<any[]>([]);

  useEffect(() => {
    const prev = revalidatorStateRef.current;
    revalidatorStateRef.current = revalidatorState;

    if (prev !== "loading" && revalidatorState === "loading") {
      // Revalidation just started — buffer any live picks to avoid loss
      isRevalidatingRef.current = true;
      pendingPicksDuringRevalidationRef.current = [];
    } else if (prev === "loading" && revalidatorState === "idle") {
      // Revalidation just completed — merge DB snapshot with buffered picks
      isRevalidatingRef.current = false;
      const dbPickIds = new Set(draftPicks.map((p: any) => p.id));
      const missedPicks = pendingPicksDuringRevalidationRef.current.filter(
        (p: any) => !dbPickIds.has(p.id)
      );
      pendingPicksDuringRevalidationRef.current = [];

      setPicks([...draftPicks, ...missedPicks]);
      setCurrentPick(season.currentPickNumber || 1);
      setIsPaused(season.draftPaused || false);
      setIsDraftComplete(
        season.status === "active" || season.status === "completed"
      );
      // Sync the queue — participants drafted while we were away will have
      // been removed server-side, but we never received those
      // `participant-removed-from-queues` events. The loader re-fetches
      // userQueue fresh on every revalidation so we can trust it here.
      setQueue(userQueue);
    }
  }, [revalidatorState, draftPicks, season]);

  const [picks, setPicks] = useState(draftPicks);
  const [currentPick, setCurrentPick] = useState(season.currentPickNumber || 1);
  const [searchQuery, setSearchQuery] = useState("");
  const [hideDrafted, setHideDrafted] = useState(true);
  const [hideIneligible, setHideIneligible] = useState(true);
  const [sportFilter, setSportFilter] = useState<string>("all");
  const [queue, setQueue] = useState<QueueItem[]>(userQueue);
  const [isPaused, setIsPaused] = useState(season.draftPaused || false);
  const [isDraftComplete, setIsDraftComplete] = useState(
    season.status === "active" || season.status === "completed"
  );

  // Sidebar and tabs state
  const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
    if (typeof window === "undefined") return false;
    const stored = localStorage.getItem("draftSidebarCollapsed");
    return stored ? JSON.parse(stored) : false;
  });
  const [activeTab, setActiveTab] = useState<"participants" | "board" | "teams">("board");
  const [mobileTab, setMobileTab] = useState<"available" | "queue" | "board" | "roster" | "controls">(
    !userTeam && isCommissioner ? "board" : "available"
  );
  const isMobile = useMediaQuery("(max-width: 767px)");

  // Track autodraft status for all teams
  const [autodraftStatus, setAutodraftStatus] = useState<Record<string, boolean>>(() => {
    const status: Record<string, boolean> = {};
    autodraftSettings.forEach((setting: any) => {
      status[setting.teamId] = setting.isEnabled;
    });
    return status;
  });

  // Track connected teams
  const [connectedTeams, setConnectedTeams] = useState<Set<string>>(new Set());

  const [teamTimers, setTeamTimers] = useState<Record<string, number>>(() => {
    // Initialize with timers from loader data, or use initial time if draft hasn't started
    const timersMap: Record<string, number> = {};
    const initialTime = season.draftInitialTime || 120;
    
    if (timers.length > 0) {
      // Draft has started, use actual timers
      timers.forEach((timer: any) => {
        timersMap[timer.teamId] = timer.timeRemaining;
      });
    } else {
      // Draft hasn't started, show initial time for all teams
      draftSlots.forEach((slot) => {
        timersMap[slot.team.id] = initialTime;
      });
    }
    
    return timersMap;
  });
  const [forcePickDialogOpen, setForcePickDialogOpen] = useState(false);
  const [selectedPickSlot, setSelectedPickSlot] = useState<{
    pickNumber: number;
    teamId: string;
  } | null>(null);
  // Replace pick dialog state
  const [replacePickDialogOpen, setReplacePickDialogOpen] = useState(false);
  const [replacePickSlot, setReplacePickSlot] = useState<{
    pickNumber: number;
    teamId: string;
    oldParticipantId: string;
  } | null>(null);

  // Rollback confirm dialog state
  const [rollbackConfirmOpen, setRollbackConfirmOpen] = useState(false);
  const [rollbackPickNumber, setRollbackPickNumber] = useState<number | null>(null);
  const [isRollingBack, setIsRollingBack] = useState(false);

  // Time bank adjustment dialog state
  const [timeBankDialogOpen, setTimeBankDialogOpen] = useState(false);
  const [timeBankTeamId, setTimeBankTeamId] = useState<string | null>(null);
  const [timeBankAmount, setTimeBankAmount] = useState("1");
  const [timeBankUnit, setTimeBankUnit] = useState<"seconds" | "minutes" | "hours">("minutes");
  const [timeBankDirection, setTimeBankDirection] = useState<"add" | "remove">("add");
  const [isAdjustingTimeBank, setIsAdjustingTimeBank] = useState(false);

  // Shared transforms for eligibility calculations
  const transformedPicks = useMemo(
    () =>
      picks.map((p: any) => ({
        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: any) => ({
        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()).sort((a, b) =>
      a.name.localeCompare(b.name)
    );
  }, [availableParticipants]);

  // Calculate draft eligibility for current user's team
  const eligibility = useMemo(() => {
    if (!userTeam) return null;
    const userTeamPicks = transformedPicks.filter(
      (p: any) => 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: any) => 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: any) => p.participant.id !== replacePickSlot.oldParticipantId
    );
    const selectedTeamPicks = allPicksExcluding.filter(
      (p: any) => p.teamId === replacePickSlot.teamId
    );
    return calculateDraftEligibility(
      replacePickSlot.teamId,
      selectedTeamPicks,
      allPicksExcluding,
      transformedParticipants,
      seasonSportsData,
      season.draftRounds,
      season.teams
    );
  }, [replacePickSlot, transformedPicks, transformedParticipants, seasonSportsData, season]);

  // Listen for new picks from other users
  useEffect(() => {
    const handlePickMade = (data: any) => {
      if (isRevalidatingRef.current) {
        // Buffer this pick; the revalidation-complete handler will merge it
        // into the DB snapshot so it isn't silently dropped.
        // Don't update currentPick either — the sync effect will set it from
        // fresh season.currentPickNumber once loading → idle, keeping the
        // pick counter and the picks list in sync with each other.
        pendingPicksDuringRevalidationRef.current.push(data.pick);
      } else {
        setPicks((prev: any) => [...prev, data.pick]);
        setCurrentPick(data.nextPickNumber);
      }

      // No meaningful "next turn" notification once the draft is over
      if (data.isDraftComplete) return;

      const notifTitle = `${season.league.name} Draft`;
      const nextSlot = getTeamForPick(data.nextPickNumber, draftSlots);
      const isNowMyTurn = !!(
        userTeam && nextSlot && nextSlot.team.id === userTeam.id
      );

      if (isNowMyTurn) {
        sendNotificationRef.current(notifTitle, `It's your turn to pick!`);
      } else if (
        notificationsModeRef.current === "all_picks" &&
        data.pick?.team?.id !== userTeam?.id
      ) {
        // Only notify about other teams' picks, not the user's own
        const pickerName = data.pick?.team?.name || "A team";
        const participantName = data.pick?.participant?.name || "a participant";
        sendNotificationRef.current(
          notifTitle,
          `${pickerName} picked ${participantName}`
        );
      }
    };

    const handleTimerUpdate = (data: any) => {
      // Update the specific team's timer
      setTeamTimers((prev) => ({
        ...prev,
        [data.teamId]: data.timeRemaining,
      }));
    };

    const handleDraftPaused = () => {
      setIsPaused(true);
    };

    const handleDraftResumed = () => {
      setIsPaused(false);
    };

    const handleDraftCompleted = () => {
      setIsDraftComplete(true);
    };

    const handleAutodraftUpdated = (data: { teamId: string; isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }) => {
      setAutodraftStatus((prev) => ({
        ...prev,
        [data.teamId]: data.isEnabled,
      }));

      // Update user's local state if it's their team
      if (userTeam && data.teamId === userTeam.id) {
        // Detect server-side auto-disable: was enabled with queueOnly, now disabled
        const prev = userAutodraftRef.current;
        if (!data.isEnabled && prev.isEnabled && prev.queueOnly) {
          toast.info("Autodraft disabled — your queue is empty");
        }

        setUserAutodraft({
          isEnabled: data.isEnabled,
          mode: data.mode,
          queueOnly: data.queueOnly,
        });
      }
    };

    const handleTeamConnected = (data: { teamId: string }) => {
      setConnectedTeams((prev) => new Set(prev).add(data.teamId));
    };

    const handleTeamDisconnected = (data: { teamId: string }) => {
      setConnectedTeams((prev) => {
        const newSet = new Set(prev);
        newSet.delete(data.teamId);
        return newSet;
      });
    };

    const handleConnectedTeamsList = (data: { teamIds: string[] }) => {
      setConnectedTeams(new Set(data.teamIds));
    };

    const handleParticipantRemovedFromQueues = (data: { participantId: string }) => {
      setQueue((prev: any) =>
        prev.filter((item: any) => item.participantId !== data.participantId)
      );
    };

    const handlePickReplaced = (data: any) => {
      setPicks((prev: any) =>
        prev.map((p: any) => (p.pickNumber === data.pickNumber ? data.pick : p))
      );
    };

    const handleDraftRolledBack = (data: any) => {
      setPicks((prev: any) =>
        prev.filter((p: any) => p.pickNumber < data.pickNumber)
      );
      setCurrentPick(data.pickNumber);
      setIsDraftComplete(false);
      setIsPaused(false);
    };

    on("pick-made", handlePickMade);
    on("timer-update", handleTimerUpdate);
    on("draft-paused", handleDraftPaused);
    on("draft-resumed", handleDraftResumed);
    on("draft-completed", handleDraftCompleted);
    on("autodraft-updated", handleAutodraftUpdated);
    on("team-connected", handleTeamConnected);
    on("team-disconnected", handleTeamDisconnected);
    on("connected-teams-list", handleConnectedTeamsList);
    on("participant-removed-from-queues", handleParticipantRemovedFromQueues);
    on("pick-replaced", handlePickReplaced);
    on("draft-rolled-back", handleDraftRolledBack);

    return () => {
      off("pick-made", handlePickMade);
      off("timer-update", handleTimerUpdate);
      off("draft-paused", handleDraftPaused);
      off("draft-resumed", handleDraftResumed);
      off("draft-completed", handleDraftCompleted);
      off("autodraft-updated", handleAutodraftUpdated);
      off("team-connected", handleTeamConnected);
      off("team-disconnected", handleTeamDisconnected);
      off("connected-teams-list", handleConnectedTeamsList);
      off("participant-removed-from-queues", handleParticipantRemovedFromQueues);
      off("pick-replaced", handlePickReplaced);
      off("draft-rolled-back", handleDraftRolledBack);
    };
  // `on`/`off` are stable useCallback refs — this effect runs once per socket instance.
  // `draftSlots`, `userTeam`, and `season.league.name` are intentionally omitted: they
  // come from useLoaderData and are immutable for the lifetime of the page load.
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [on, off]);

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

  // Queue handlers
  const handleAddToQueue = 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);

    try {
      const response = await fetch("/api/queue/add", {
        method: "POST",
        body: formData,
      });

      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 (error) {
      // 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");
    }
  };

  const handleRemoveFromQueue = 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);

    try {
      const response = await fetch("/api/queue/remove", {
        method: "POST",
        body: formData,
      });

      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");
    }
  };

  const handleReorderQueue = 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));

    try {
      const response = await fetch("/api/queue/reorder", {
        method: "POST",
        body: formData,
      });

      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");
    }
  };

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

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

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

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

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

      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 fetch("/api/draft/resume", {
        method: "POST",
        body: formData,
      });

      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 = async (participantId: string) => {
    const formData = new FormData();
    formData.append("seasonId", season.id);
    formData.append("participantId", participantId);

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

    if (!response.ok) {
      const error = await response.json();
      toast.error(error.error || "Failed to make pick");
    }
  };

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

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

    if (!response.ok) {
      const error = await response.json();
      toast.error(error.error || "Failed to force autopick");
    }
  };

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

    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 fetch("/api/draft/force-manual-pick", {
      method: "POST",
      body: formData,
    });

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

  const handleReplacePickOpen = (pickNumber: number, teamId: string) => {
    const pick = picks.find((p: any) => p.pickNumber === pickNumber);
    if (!pick) {
      toast.error("Pick not found — try refreshing the page");
      return;
    }
    setReplacePickSlot({ pickNumber, teamId, oldParticipantId: pick.participant.id });
    setReplacePickDialogOpen(true);
  };

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

    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 fetch("/api/draft/replace-pick", {
      method: "POST",
      body: formData,
    });

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

  const handleRollbackToPick = (pickNumber: number) => {
    setRollbackPickNumber(pickNumber);
    setRollbackConfirmOpen(true);
  };

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

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

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

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

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

  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 fetch("/api/draft/adjust-time-bank", {
        method: "POST",
        body: formData,
      });

      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 = (pickNumber: number, teamId: string) => {
    setSelectedPickSlot({ pickNumber, teamId });
    setForcePickDialogOpen(true);
  };

  // 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 grid: Array<
      Array<{
        pickNumber: number;
        round: number;
        pickInRound: number;
        teamId: string;
        pick?: any;
      }>
    > = [];

    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 = picks.find((p: any) => p.pickNumber === pickNumber);

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

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

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

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

  // Filter participants based on search, sport, drafted status, and eligibility
  const filteredParticipants = useMemo(
    () =>
      availableParticipants.filter((participant: any) => {
        // Drafted filter - hide drafted participants by default
        if (hideDrafted && draftedParticipantIds.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;
          }
        }
        // Search filter
        if (
          searchQuery &&
          !participant.name.toLowerCase().includes(searchQuery.toLowerCase())
        ) {
          return false;
        }
        // Sport filter
        if (sportFilter !== "all" && participant.sport.name !== sportFilter) {
          return false;
        }
        return true;
      }),
    [availableParticipants, hideDrafted, hideIneligible, eligibility, draftedParticipantIds, searchQuery, sportFilter]
  );

  // Shared component props — defined once to avoid duplication between desktop and mobile layouts
  const availableParticipantsSectionProps = {
    participants: filteredParticipants,
    searchQuery,
    sportFilter,
    hideDrafted,
    hideIneligible,
    uniqueSports,
    draftedParticipantIds,
    queue,
    eligibility,
    canPick,
    hasTeam: !!userTeam,
    onSearchChange: setSearchQuery,
    onSportFilterChange: setSportFilter,
    onHideDraftedChange: setHideDrafted,
    onHideIneligibleChange: setHideIneligible,
    onMakePick: handleMakePick,
    onAddToQueue: handleAddToQueue,
    onRemoveFromQueue: handleRemoveFromQueue,
  };

  const draftGridSectionProps = {
    draftSlots,
    draftGrid,
    currentPick,
    teamTimers,
    autodraftStatus,
    connectedTeams,
    isCommissioner,
    ownerMap,
    onAdjustTimeBankOpen: isCommissioner ? handleAdjustTimeBankOpen : undefined,
    onForceAutopick: handleForceAutopick,
    onForceManualPickOpen: handleForceManualPickOpen,
    onReplacePick: isCommissioner ? handleReplacePickOpen : undefined,
    onRollbackToPick: isCommissioner && !isDraftComplete ? handleRollbackToPick : undefined,
  };

  const teamsDraftedGridProps = {
    draftSlots,
    picks,
    sports: seasonSportsData,
    season: { numFlexPicks },
    ownerMap,
  };

  const queueSectionProps = userTeam
    ? {
        queue,
        availableParticipants,
        seasonId: season.id,
        teamId: userTeam.id,
        isMyTurn,
        canPick,
        userAutodraft,
        onRemoveFromQueue: handleRemoveFromQueue,
        onAutodraftUpdate: (isEnabled: boolean, mode: "next_pick" | "while_on", queueOnly: boolean) => {
          setUserAutodraft({ isEnabled, mode, queueOnly });
        },
        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">
          🎉 Draft Complete! The season is now active.
          {season.league.isPublicDraftBoard && (
            <>
              {" "}
              <a
                href={`/leagues/${season.leagueId}/draft-board/${season.id}`}
                className="underline hover:text-emerald-300"
              >
                View Draft Board
              </a>
            </>
          )}
        </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>
                    <line x1="3" y1="6" x2="21" y2="6"></line>
                    <line x1="3" y1="18" x2="21" y2="18"></line>
                  </svg>
                </Button>
              )}
              <div>
                <h1 className="text-lg md:text-3xl font-bold">
                  {season.league.name} - {season.year} Draft
                </h1>
                <div className="flex gap-4 text-sm text-muted-foreground mt-1">
                  <span>Round: {currentRound}</span>
                  <span>Pick: {currentPick}</span>
                  <span className="capitalize">
                    {season.status.replace("_", " ")}
                  </span>
                </div>
              </div>
            </div>
            <div className="flex items-center gap-3">
              {/* Commissioner Controls - hidden on mobile (shown in Controls tab) */}
              {isCommissioner && season.status === "pre_draft" && (
                <Button className="hidden md:flex" onClick={handleStartDraft}>Start Draft</Button>
              )}

              {isCommissioner && season.status === "draft" && !isDraftComplete && (
                <div className="hidden md:flex">
                  {isPaused ? (
                    <Button onClick={handleResumeDraft} variant="default">
                      Resume Draft
                    </Button>
                  ) : (
                    <Button onClick={handlePauseDraft} variant="outline">
                      Pause Draft
                    </Button>
                  )}
                </div>
              )}

              <div className="flex items-center gap-2">
                <div
                  className={`w-3 h-3 rounded-full ${
                    isConnected ? "bg-emerald-500" : "bg-coral-accent"
                  }`}
                />
                <span className="hidden sm:inline text-sm font-medium">
                  {isConnected ? "Connected" : "Disconnected"}
                </span>
              </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 className={`md:hidden flex-shrink-0 flex items-center justify-between px-4 py-2 border-b ${
          isMyTurn
            ? "bg-electric/25 border-electric"
            : "bg-muted/30"
        }`}>
          <div>
            <div className={`text-xs font-bold uppercase tracking-wider ${isMyTurn ? "text-electric" : "text-muted-foreground"}`}>
              {isMyTurn ? "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>
          ) : (
            <span className={`text-xl font-mono font-bold tabular-nums ${currentClockColor}`}>
              {formatClockTime(currentClockTime)}
            </span>
          )}
        </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" && (
              <AvailableParticipantsSection {...availableParticipantsSectionProps} />
            )}
            {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" && (
              <DraftGridSection {...draftGridSectionProps} />
            )}
            {mobileTab === "roster" && (
              <TeamsDraftedGrid {...teamsDraftedGridProps} />
            )}
            {mobileTab === "controls" && (
              <div className="h-full overflow-y-auto p-4 space-y-6">
                {isCommissioner && season.status === "pre_draft" && (
                  <Button className="w-full min-h-[48px]" onClick={handleStartDraft}>
                    Start Draft
                  </Button>
                )}
                {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>
                  )
                )}

                <section>
                  <h2 className="font-semibold text-sm mb-2">Recent Picks</h2>
                  <SidebarRecentPicks picks={picks} />
                </section>

                <NotificationSettings
                  enabled={notificationsEnabled}
                  onEnabledChange={setNotificationsEnabled}
                  mode={notificationsMode}
                  onModeChange={setNotificationsMode}
                  permissionState={notificationsPermission}
                />

                <Button variant="outline" asChild className="w-full min-h-[48px]">
                  <Link to={`/leagues/${season.leagueId}`}>Exit Draft Room</Link>
                </Button>
              </div>
            )}
          </div>
        ) : (
          <div className="flex h-full overflow-hidden">
            {userTeam && queueSectionProps && (
              <DraftSidebar
                collapsed={sidebarCollapsed}
                onCollapsedChange={setSidebarCollapsed}
                queueSection={<QueueSection {...queueSectionProps} />}
                recentPicksSection={<SidebarRecentPicks picks={picks} />}
                settingsSection={
                  <NotificationSettings
                    enabled={notificationsEnabled}
                    onEnabledChange={setNotificationsEnabled}
                    mode={notificationsMode}
                    onModeChange={setNotificationsMode}
                    permissionState={notificationsPermission}
                  />
                }
              />
            )}

            <div className="flex-1 overflow-hidden">
              <Tabs
                value={activeTab}
                onValueChange={(value) =>
                  setActiveTab(value as "participants" | "board" | "teams")
                }
                className="h-full flex flex-col"
              >
                <div className={`mt-4 transition-all duration-300 ${
                  isMyTurn && season.status === "draft" && !isDraftComplete
                    ? "bg-electric/25 border-y-2 border-electric shadow-[0_0_24px_0_rgb(0_200_255_/_0.18)]"
                    : ""
                }`}>
                  <div className="flex items-center gap-3 px-4 py-2">
                    <TabsList>
                      <TabsTrigger value="participants">Available Participants</TabsTrigger>
                      <TabsTrigger value="board">Draft Board</TabsTrigger>
                      <TabsTrigger value="teams">Teams Drafted</TabsTrigger>
                    </TabsList>

                    {season.status === "draft" && !isDraftComplete && currentDraftSlot && (
                      <div className={`ml-auto flex items-center gap-2.5 rounded-lg px-3 py-1.5 flex-shrink-0 transition-all ${
                        isMyTurn
                          ? "bg-electric/30 border-2 border-electric shadow-md shadow-electric/30"
                          : "border border-border/50"
                      }`}>
                        <div className="leading-tight">
                          <div className={`text-xs font-bold uppercase tracking-wider ${isMyTurn ? "text-electric" : "text-muted-foreground"}`}>
                            {isMyTurn ? "Your Turn!" : "On the Clock"}
                          </div>
                          <div className={`text-sm font-bold ${isMyTurn ? "text-foreground" : "text-muted-foreground"}`}>
                            {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>
                        ) : (
                          <span className={`text-2xl font-mono font-bold tabular-nums ${currentClockColor}`}>
                            {formatClockTime(currentClockTime)}
                          </span>
                        )}
                      </div>
                    )}
                  </div>
                </div>

                <TabsContent value="participants" className="flex-1 overflow-hidden m-0">
                  <AvailableParticipantsSection {...availableParticipantsSectionProps} />
                </TabsContent>

                <TabsContent value="board" className="flex-1 overflow-hidden m-0">
                  <DraftGridSection {...draftGridSectionProps} />
                </TabsContent>

                <TabsContent value="teams" className="flex-1 overflow-hidden m-0">
                  <TeamsDraftedGrid {...teamsDraftedGridProps} />
                </TabsContent>
              </Tabs>
            </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={availableParticipants}
        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={availableParticipants}
        draftedParticipantIds={draftedParticipantIds}
        allowParticipantId={replacePickSlot?.oldParticipantId}
        currentParticipantId={replacePickSlot?.oldParticipantId}
        eligibility={replacePickEligibility}
        uniqueSports={uniqueSports}
        onSelect={handleReplacePick}
      />

      {/* Rollback Confirmation Dialog */}
      <Dialog
        open={rollbackConfirmOpen}
        onOpenChange={(open) => {
          setRollbackConfirmOpen(open);
          if (!open) setRollbackPickNumber(null);
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Roll Back Draft</DialogTitle>
            <DialogDescription>
              {rollbackPickNumber !== null && (() => {
                const count = picks.filter((p: any) => p.pickNumber >= rollbackPickNumber).length;
                return `This will erase ${count} pick${count === 1 ? "" : "s"} (pick #${rollbackPickNumber} through the most recent) and return the draft to pick #${rollbackPickNumber}. This cannot be undone.`;
              })()}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setRollbackConfirmOpen(false)}>
              Cancel
            </Button>
            <Button variant="destructive" onClick={handleConfirmRollback} disabled={isRollingBack}>
              {isRollingBack ? "Rolling Back..." : "Roll Back"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Time Bank Adjustment Dialog */}
      <Dialog
        open={timeBankDialogOpen}
        onOpenChange={(open) => {
          setTimeBankDialogOpen(open);
          if (!open) setTimeBankTeamId(null);
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Adjust Time Bank</DialogTitle>
            <DialogDescription>
              {timeBankTeamId
                ? `Adjusting time for ${draftSlots.find((s) => s.team.id === timeBankTeamId)?.team.name}`
                : "Adjust a team's time bank"}
            </DialogDescription>
          </DialogHeader>

          <div className="flex flex-col gap-4 py-2">
            <div className="flex gap-2">
              <button
                type="button"
                onClick={() => setTimeBankDirection("add")}
                className={`flex-1 py-2 rounded-md border text-sm font-medium transition-colors ${
                  timeBankDirection === "add"
                    ? "bg-emerald-500/20 border-emerald-500 text-emerald-400"
                    : "border-border text-muted-foreground hover:bg-muted"
                }`}
              >
                Add Time
              </button>
              <button
                type="button"
                onClick={() => setTimeBankDirection("remove")}
                className={`flex-1 py-2 rounded-md border text-sm font-medium transition-colors ${
                  timeBankDirection === "remove"
                    ? "bg-destructive/20 border-destructive text-destructive"
                    : "border-border text-muted-foreground hover:bg-muted"
                }`}
              >
                Remove Time
              </button>
            </div>

            <div className="flex gap-2">
              <input
                type="number"
                min="0.001"
                step="any"
                value={timeBankAmount}
                onChange={(e) => setTimeBankAmount(e.target.value)}
                className="flex-1 px-3 py-2 border rounded-md bg-background text-foreground text-base md:text-sm"
                placeholder="Amount"
              />
              <select
                value={timeBankUnit}
                onChange={(e) =>
                  setTimeBankUnit(e.target.value as "seconds" | "minutes" | "hours")
                }
                className="px-3 py-2 border rounded-md bg-background text-foreground text-base md:text-sm"
              >
                <option value="seconds">Seconds</option>
                <option value="minutes">Minutes</option>
                <option value="hours">Hours</option>
              </select>
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setTimeBankDialogOpen(false)}>
              Cancel
            </Button>
            <Button
              onClick={handleConfirmAdjustTimeBank}
              disabled={isAdjustingTimeBank}
              variant={timeBankDirection === "remove" ? "destructive" : "default"}
            >
              {isAdjustingTimeBank
                ? "Adjusting..."
                : timeBankDirection === "add"
                  ? "Add Time"
                  : "Remove Time"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

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