import { useEffect, type MutableRefObject, type RefObject } from "react";
import { toast } from "sonner";
import { getTeamForPick } from "~/lib/draft-order";
import { getAutodraftLabel } from "~/components/AutodraftSettings";
import type { getDraftPicksForSeason } from "~/models/draft-pick";
import type { findDraftSlotsBySeasonId } from "~/models/draft-slot";
import type { QueueItem, AutodraftStatusEntry } from "~/hooks/useDraftRoomState";

type DraftPicks = Awaited<ReturnType<typeof getDraftPicksForSeason>>;
type DraftSlots = Awaited<ReturnType<typeof findDraftSlotsBySeasonId>>;
type DraftPick = DraftPicks[number];

interface UseDraftSocketEventsParams {
  on: (event: string, handler: (data: unknown) => void) => void;
  off: (event: string, handler: (data: unknown) => void) => void;
  socketVersion: number;
  // Loader-derived, stable for lifetime of page load
  userTeam: { id: string } | undefined;
  draftSlots: DraftSlots;
  leagueName: string;
  // Refs from useDraftAuthRecovery
  isRevalidatingRef: RefObject<boolean>;
  pendingPicksDuringRevalidationRef: MutableRefObject<DraftPicks>;
  pendingQueueMutationsRef: MutableRefObject<number>;
  userAutodraftRef: MutableRefObject<{ isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }>;
  // Notification refs from the component
  sendNotificationRef: MutableRefObject<(title: string, body: string) => void>;
  notificationsModeRef: MutableRefObject<string>;
  // State setters
  setPicks: (fn: (prev: DraftPicks) => DraftPicks) => void;
  setCurrentPick: (pick: number) => void;
  setIsPaused: (paused: boolean) => void;
  setIsDraftComplete: (complete: boolean) => void;
  setAutodraftStatus: (fn: (prev: Record<string, AutodraftStatusEntry>) => Record<string, AutodraftStatusEntry>) => void;
  setUserAutodraft: (value: { isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }) => void;
  setConnectedTeams: (fn: (prev: Set<string>) => Set<string>) => void;
  setQueue: (fn: (prev: QueueItem[]) => QueueItem[]) => void;
  setTeamTimers: (fn: (prev: Record<string, number>) => Record<string, number>) => void;
  setIsOvernightPause: (value: boolean) => void;
  setOvernightResumesAt: (value: Date | null) => void;
  setWatchedParticipantIds: (value: Set<string>) => void;
  setRoomClosed: (value: boolean) => void;
  setIsSyncing: (value: boolean) => void;
  setBracktVorps: (fn: (prev: Map<string, number>) => Map<string, number>) => void;
  setAnimatingOutParticipantId: (id: string) => void;
}

export function useDraftSocketEvents({
  on,
  off,
  socketVersion,
  userTeam,
  draftSlots,
  leagueName,
  isRevalidatingRef,
  pendingPicksDuringRevalidationRef,
  pendingQueueMutationsRef,
  userAutodraftRef,
  sendNotificationRef,
  notificationsModeRef,
  setPicks,
  setCurrentPick,
  setIsPaused,
  setIsDraftComplete,
  setAutodraftStatus,
  setUserAutodraft,
  setConnectedTeams,
  setQueue,
  setTeamTimers,
  setIsOvernightPause,
  setOvernightResumesAt,
  setWatchedParticipantIds,
  setRoomClosed,
  setIsSyncing,
  setBracktVorps,
  setAnimatingOutParticipantId,
}: UseDraftSocketEventsParams) {
  useEffect(() => {
    type PickMadePayload = {
      pick: DraftPick & { team?: { id?: string; name?: string }; participant?: { name?: string } };
      nextPickNumber: number;
      isDraftComplete?: boolean;
    };
    const handlePickMade = (data: PickMadePayload) => {
      if (isRevalidatingRef.current) {
        pendingPicksDuringRevalidationRef.current.push(data.pick);
      } else {
        setPicks((prev) => [...prev, data.pick]);
        setCurrentPick(data.nextPickNumber);
        if (data.pick?.participant?.id) {
          setAnimatingOutParticipantId(data.pick.participant.id);
        }
      }

      if (data.isDraftComplete) return;

      const notifTitle = `${leagueName} 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
      ) {
        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: {
      teamId: string;
      timeRemaining: number;
      currentPickNumber: number | null;
      overnightPauseActive?: boolean;
      resumesAtUTC?: number;
    }) => {
      setTeamTimers((prev) => {
        if (prev[data.teamId] === data.timeRemaining) return prev;
        return { ...prev, [data.teamId]: data.timeRemaining };
      });
      if (data.currentPickNumber !== null) {
        setCurrentPick(data.currentPickNumber);
      }
      const pauseActive = data.overnightPauseActive ?? false;
      setIsOvernightPause(pauseActive);
      setOvernightResumesAt(pauseActive && data.resumesAtUTC ? new Date(data.resumesAtUTC) : null);
    };

    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;
      source?: "commissioner" | "user";
    }) => {
      setAutodraftStatus((prev) => ({
        ...prev,
        [data.teamId]: { isEnabled: data.isEnabled, mode: data.mode, queueOnly: data.queueOnly },
      }));

      if (userTeam && data.teamId === userTeam.id) {
        if (data.source === "commissioner") {
          if (!data.isEnabled) {
            toast.info("Commissioner turned off your autodraft");
          } else {
            toast.info(`Commissioner changed your autodraft to "${getAutodraftLabel(data.isEnabled, data.mode, data.queueOnly)}"`);
          }
        } else {
          const prev = userAutodraftRef.current;
          if (!data.isEnabled && prev.isEnabled && prev.queueOnly && prev.mode === "while_on") {
            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) => prev.filter((item) => item.participantId !== data.participantId));
    };

    const handleQueueEligibilityPruned = (data: { teamId: string; removedParticipantIds: string[] }) => {
      if (data.teamId !== userTeam?.id) return;
      const removed = new Set(data.removedParticipantIds);
      setQueue((prev) => prev.filter((item) => !removed.has(item.participantId)));
    };

    const handleQueueUpdated = (data: { queue: QueueItem[] }) => {
      if (pendingQueueMutationsRef.current > 0) return;
      setQueue(() => data.queue);
    };

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

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

    const handleDraftStateSync = (data: {
      picks: DraftPicks;
      currentPickNumber: number;
      isPaused: boolean;
      status: string;
      timers?: Array<{ teamId: string; timeRemaining: number }>;
      queue?: QueueItem[];
      watchlistParticipantIds?: string[];
    }) => {
      if (!isRevalidatingRef.current) {
        setPicks(() => data.picks);
        setCurrentPick(data.currentPickNumber);
        setIsPaused(data.isPaused);
        setIsDraftComplete(data.status === "active" || data.status === "completed");
        if (data.timers) {
          setTeamTimers((prev) => {
            const updated = { ...prev };
            data.timers?.forEach((t) => { updated[t.teamId] = t.timeRemaining; });
            return updated;
          });
        }
        if (data.queue) {
          const q = data.queue;
          setQueue(() => q);
        }
        if (data.watchlistParticipantIds) {
          setWatchedParticipantIds(new Set(data.watchlistParticipantIds));
        }
      }
      setIsSyncing(false);
    };

    const handleWatchlistUpdated = (data: { participantIds: string[] }) => {
      setWatchedParticipantIds(new Set(data.participantIds));
    };

    const handleDraftRoomClosed = () => {
      setRoomClosed(true);
    };

    const handleBracktEvsUpdated = (data: {
      updates: Array<{ participantId: string; vorpValue: number }>;
    }) => {
      setBracktVorps((prev) => {
        const next = new Map(prev);
        for (const { participantId, vorpValue } of data.updates) {
          next.set(participantId, vorpValue);
        }
        return next;
      });
    };

    on("pick-made", handlePickMade as (data: unknown) => void);
    on("timer-update", handleTimerUpdate as (data: unknown) => void);
    on("draft-paused", handleDraftPaused as (data: unknown) => void);
    on("draft-resumed", handleDraftResumed as (data: unknown) => void);
    on("draft-completed", handleDraftCompleted as (data: unknown) => void);
    on("autodraft-updated", handleAutodraftUpdated as (data: unknown) => void);
    on("team-connected", handleTeamConnected as (data: unknown) => void);
    on("team-disconnected", handleTeamDisconnected as (data: unknown) => void);
    on("connected-teams-list", handleConnectedTeamsList as (data: unknown) => void);
    on("participant-removed-from-queues", handleParticipantRemovedFromQueues as (data: unknown) => void);
    on("queue-eligibility-pruned", handleQueueEligibilityPruned as (data: unknown) => void);
    on("queue-updated", handleQueueUpdated as (data: unknown) => void);
    on("pick-replaced", handlePickReplaced as (data: unknown) => void);
    on("draft-rolled-back", handleDraftRolledBack as (data: unknown) => void);
    on("draft-state-sync", handleDraftStateSync as (data: unknown) => void);
    on("watchlist-updated", handleWatchlistUpdated as (data: unknown) => void);
    on("draft-room-closed", handleDraftRoomClosed as (data: unknown) => void);
    on("brackt-evs-updated", handleBracktEvsUpdated as (data: unknown) => void);

    return () => {
      off("pick-made", handlePickMade as (data: unknown) => void);
      off("timer-update", handleTimerUpdate as (data: unknown) => void);
      off("draft-paused", handleDraftPaused as (data: unknown) => void);
      off("draft-resumed", handleDraftResumed as (data: unknown) => void);
      off("draft-completed", handleDraftCompleted as (data: unknown) => void);
      off("autodraft-updated", handleAutodraftUpdated as (data: unknown) => void);
      off("team-connected", handleTeamConnected as (data: unknown) => void);
      off("team-disconnected", handleTeamDisconnected as (data: unknown) => void);
      off("connected-teams-list", handleConnectedTeamsList as (data: unknown) => void);
      off("participant-removed-from-queues", handleParticipantRemovedFromQueues as (data: unknown) => void);
      off("queue-eligibility-pruned", handleQueueEligibilityPruned as (data: unknown) => void);
      off("queue-updated", handleQueueUpdated as (data: unknown) => void);
      off("pick-replaced", handlePickReplaced as (data: unknown) => void);
      off("draft-rolled-back", handleDraftRolledBack as (data: unknown) => void);
      off("draft-state-sync", handleDraftStateSync as (data: unknown) => void);
      off("watchlist-updated", handleWatchlistUpdated as (data: unknown) => void);
      off("draft-room-closed", handleDraftRoomClosed as (data: unknown) => void);
      off("brackt-evs-updated", handleBracktEvsUpdated as (data: unknown) => void);
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [on, off, socketVersion]);
}
