'use client';

import { useCallback, useState } from 'react';
import {
  getPlayerProps,
  getTeamProps,
  getTeamPropsBreakdown,
  isLoggedIn,
  unlockDvpInsight,
  unlockHcwInsight,
  unlockPlayerProp,
  unlockSharpInsight,
  unlockSteamInsight,
} from '@/lib/api';
import { buildUnlockedPlayerPropPatch, shouldUsePerPlayerProps } from '@/lib/player-props';
import {
  type PublicFeaturedPlayer,
  type PublicForecastRouteResponseV1,
  type PublicInsightAvailability,
  type PublicPlayerProp,
  type PublicPlayerPropMarket,
} from '@/contracts/forecast-public';
import type { ForecastModalState } from '@/lib/forecast-modal';
import type { SignupGateContext } from '@/components/forecast-page-types';

interface UseForecastUnlockStateArgs {
  user: any;
  openSignupGate: (context: string | SignupGateContext, resumeAction?: () => void | Promise<void>) => void;
  openPaywall: (source: string) => void;
  refreshUserPreservingBalance: () => void;
  updateBalanceFromResponse: (data: any) => void;
  setShowVerifyPrompt: (value: boolean) => void;
}

type IsCurrentRequest = (requestId: number, eventId: string) => boolean;

const DEFAULT_INSIGHT_AVAILABILITY: PublicInsightAvailability = {
  steam: false,
  sharp: false,
  dvp: false,
  hcw: false,
};

export function resolveInsightAvailability(
  data: Pick<PublicForecastRouteResponseV1, 'insightAvailability'>,
): PublicInsightAvailability {
  if (!data.insightAvailability || typeof data.insightAvailability !== 'object') {
    return DEFAULT_INSIGHT_AVAILABILITY;
  }

  return {
    ...DEFAULT_INSIGHT_AVAILABILITY,
    ...data.insightAvailability,
  };
}

export default function useForecastUnlockState({
  user,
  openSignupGate,
  openPaywall,
  refreshUserPreservingBalance,
  updateBalanceFromResponse,
  setShowVerifyPrompt,
}: UseForecastUnlockStateArgs) {
  const [teamPropsLoading, setTeamPropsLoading] = useState<'home' | 'away' | null>(null);
  const [homePropsData, setHomePropsData] = useState<any>(null);
  const [awayPropsData, setAwayPropsData] = useState<any>(null);
  const [gamePropsBreakdown, setGamePropsBreakdown] = useState<any>(null);
  const [homePropsUnlocked, setHomePropsUnlocked] = useState(false);
  const [awayPropsUnlocked, setAwayPropsUnlocked] = useState(false);
  const [steamInsightLoading, setSteamInsightLoading] = useState(false);
  const [sharpInsightLoading, setSharpInsightLoading] = useState(false);
  const [steamInsightData, setSteamInsightData] = useState<any>(null);
  const [sharpInsightData, setSharpInsightData] = useState<any>(null);
  const [steamInsightUnlocked, setSteamInsightUnlocked] = useState(false);
  const [sharpInsightUnlocked, setSharpInsightUnlocked] = useState(false);
  const [dvpInsightLoading, setDvpInsightLoading] = useState(false);
  const [dvpInsightData, setDvpInsightData] = useState<any>(null);
  const [dvpInsightUnlocked, setDvpInsightUnlocked] = useState(false);
  const [hcwInsightLoading, setHcwInsightLoading] = useState(false);
  const [hcwInsightData, setHcwInsightData] = useState<any>(null);
  const [hcwInsightUnlocked, setHcwInsightUnlocked] = useState(false);
  const [insightAvailability, setInsightAvailability] = useState(DEFAULT_INSIGHT_AVAILABILITY);
  const [perPlayerMode, setPerPlayerMode] = useState(false);
  const [playerPropsAssets, setPlayerPropsAssets] = useState<PublicPlayerProp[]>([]);
  const [playerPropMarkets, setPlayerPropMarkets] = useState<PublicPlayerPropMarket[]>([]);
  const [featuredPlayers, setFeaturedPlayers] = useState<PublicFeaturedPlayer[]>([]);
  const [playerPropsFallbackReason, setPlayerPropsFallbackReason] = useState<'no_precomputed_assets' | 'all_assets_filtered_out' | 'game_started' | null>(null);
  const [playerPropUnlocking, setPlayerPropUnlocking] = useState<string | null>(null);
  const [notReadyRetrying, setNotReadyRetrying] = useState(false);
  const hasUnlimitedAccess = !!user?.is_weatherman || !!user?.daily_pass_valid;

  const resetForecastUnlockState = useCallback(() => {
    setHomePropsData(null);
    setAwayPropsData(null);
    setGamePropsBreakdown(null);
    setHomePropsUnlocked(false);
    setAwayPropsUnlocked(false);
    setPerPlayerMode(false);
    setPlayerPropsAssets([]);
    setPlayerPropMarkets([]);
    setFeaturedPlayers([]);
    setPlayerPropsFallbackReason(null);
    setSteamInsightData(null);
    setSharpInsightData(null);
    setDvpInsightData(null);
    setHcwInsightData(null);
    setSteamInsightUnlocked(false);
    setSharpInsightUnlocked(false);
    setDvpInsightUnlocked(false);
    setHcwInsightUnlocked(false);
    setInsightAvailability(DEFAULT_INSIGHT_AVAILABILITY);
  }, []);

  const applyUnlockedForecastState = useCallback((data: any) => {
    setSteamInsightData(data.unlockedInsightData?.STEAM || null);
    setSharpInsightData(data.unlockedInsightData?.SHARP || null);
    setDvpInsightData(data.unlockedInsightData?.DVP || null);
    setHcwInsightData(data.unlockedInsightData?.HCW || null);
    setSteamInsightUnlocked(hasUnlimitedAccess || data.unlockedInsights?.includes('STEAM') || false);
    setSharpInsightUnlocked(hasUnlimitedAccess || data.unlockedInsights?.includes('SHARP') || false);
    setDvpInsightUnlocked(hasUnlimitedAccess || data.unlockedInsights?.includes('DVP') || false);
    setHcwInsightUnlocked(hasUnlimitedAccess || data.unlockedInsights?.includes('HCW') || false);
    setInsightAvailability(resolveInsightAvailability(data));
  }, [hasUnlimitedAccess]);

  const applyPublicForecastState = useCallback((data: any) => {
    setInsightAvailability(resolveInsightAvailability(data));
    if (data.playerPropsMode === 'per_player' && Array.isArray(data.playerPropsAssets) && data.playerPropsAssets.length > 0) {
      setPerPlayerMode(true);
      setPlayerPropsAssets(data.playerPropsAssets);
      setPlayerPropMarkets([]);
      setFeaturedPlayers([]);
      setPlayerPropsFallbackReason(null);
      return;
    }

    setPerPlayerMode(false);
    setPlayerPropsAssets([]);
    setPlayerPropMarkets([]);
    setFeaturedPlayers([]);
    setPlayerPropsFallbackReason(null);
  }, []);

  const loadPlayerPropsStatus = useCallback(async (
    requestId: number,
    eventId: string,
    isCurrentRequest: IsCurrentRequest,
  ) => {
    try {
      const data = await getPlayerProps(eventId);
      if (!isCurrentRequest(requestId, eventId)) {
        return;
      }

      if (shouldUsePerPlayerProps(data)) {
        setPerPlayerMode(true);
        setPlayerPropsAssets(data.playerProps || []);
        setPlayerPropMarkets([]);
        setFeaturedPlayers(data.featuredPlayers || []);
        setPlayerPropsFallbackReason(null);
        if (data.forecastBalance !== undefined || data.forecast_balance !== undefined) {
          updateBalanceFromResponse(data);
        }
        return;
      }

      setPerPlayerMode(false);
      setPlayerPropsAssets([]);
      setPlayerPropMarkets(Array.isArray(data.marketProps) ? data.marketProps : []);
      setFeaturedPlayers(data.featuredPlayers || []);
      setPlayerPropsFallbackReason(data.fallbackReason ?? null);
    } catch {
      if (!isCurrentRequest(requestId, eventId)) {
        return;
      }

      setPerPlayerMode(false);
      setPlayerPropsAssets([]);
      setPlayerPropMarkets([]);
      setFeaturedPlayers([]);
      setPlayerPropsFallbackReason(null);
    }
  }, [updateBalanceFromResponse]);

  const loadGamePropsBreakdown = useCallback(async (
    requestId: number,
    eventId: string,
    isCurrentRequest: IsCurrentRequest,
  ) => {
    try {
      const breakdown = await getTeamPropsBreakdown(eventId);
      if (!isCurrentRequest(requestId, eventId)) {
        return;
      }
      setGamePropsBreakdown(breakdown);
    } catch {}
  }, []);

  const primeUnlimitedForecast = useCallback(async (eventId: string, league: string, baseData: any) => {
    if (!hasUnlimitedAccess) {
      return baseData;
    }

    const data = { ...baseData };
    const unlockedInsights = new Set<string>(Array.isArray(data.unlockedInsights) ? data.unlockedInsights : []);
    const unlockedInsightData = { ...(data.unlockedInsightData || {}) };

    const insightJobs: Promise<void>[] = [];
    if (data.insightAvailability?.steam && !unlockedInsightData.STEAM) {
      insightJobs.push(unlockSteamInsight(eventId, league).then((res) => {
        unlockedInsights.add('STEAM');
        unlockedInsightData.STEAM = res.insightData;
      }).catch(() => {}));
    }
    if (data.insightAvailability?.sharp && !unlockedInsightData.SHARP) {
      insightJobs.push(unlockSharpInsight(eventId, league).then((res) => {
        unlockedInsights.add('SHARP');
        unlockedInsightData.SHARP = res.insightData;
      }).catch(() => {}));
    }
    if (data.insightAvailability?.dvp && !unlockedInsightData.DVP) {
      insightJobs.push(unlockDvpInsight(eventId, league).then((res) => {
        unlockedInsights.add('DVP');
        unlockedInsightData.DVP = res.insightData;
      }).catch(() => {}));
    }
    if (data.insightAvailability?.hcw && !unlockedInsightData.HCW) {
      insightJobs.push(unlockHcwInsight(eventId, league).then((res) => {
        unlockedInsights.add('HCW');
        unlockedInsightData.HCW = res.insightData;
      }).catch(() => {}));
    }

    const sideJobs: Promise<void>[] = [
      getTeamProps(eventId, 'home', league).then((res) => {
        setHomePropsData(res);
        setHomePropsUnlocked(true);
      }).catch(() => {}),
      getTeamProps(eventId, 'away', league).then((res) => {
        setAwayPropsData(res);
        setAwayPropsUnlocked(true);
      }).catch(() => {}),
    ];

    let playerPropsJob: Promise<void> | null = null;
    if (shouldUsePerPlayerProps(data) && Array.isArray(data.playerProps)) {
      playerPropsJob = Promise.all(
        data.playerProps.map((prop: any) => unlockPlayerProp(prop.assetId)
          .then((res) => ({ assetId: prop.assetId, patch: buildUnlockedPlayerPropPatch(res) }))
          .catch(() => null)),
      ).then((patches) => {
        setPerPlayerMode(true);
        setPlayerPropsAssets((data.playerProps || []).map((prop: any) => {
          const match = patches.find((patch: any) => patch && patch.assetId === prop.assetId);
          return match ? { ...prop, ...match.patch } : prop;
        }));
        setPlayerPropsFallbackReason(null);
      }).catch(() => {});
    }

    await Promise.all([...insightJobs, ...sideJobs, ...(playerPropsJob ? [playerPropsJob] : [])]);

    data.unlockedInsights = Array.from(unlockedInsights);
    data.unlockedInsightData = unlockedInsightData;
    return data;
  }, [hasUnlimitedAccess]);

  const handleTeamPropsClick = useCallback(async (
    forecast: ForecastModalState | null,
    team: 'home' | 'away',
    retry: () => void | Promise<void>,
  ) => {
    if (!forecast) return;
    if (!isLoggedIn()) {
      openSignupGate('team_props', retry);
      return;
    }

    const eventId = forecast.eventId || '';
    const league = forecast.league || '';
    setTeamPropsLoading(team);
    try {
      const data = await getTeamProps(eventId, team, league);
      updateBalanceFromResponse(data);
      if (team === 'home') {
        setHomePropsData(data);
        setHomePropsUnlocked(true);
      } else {
        setAwayPropsData(data);
        setAwayPropsUnlocked(true);
      }
      refreshUserPreservingBalance();
    } catch (err: any) {
      if (err.status === 403 && err.data?.needsVerification) setShowVerifyPrompt(true);
      else if (err.status === 402) openPaywall('team_props');
      else if (err.status === 401) openSignupGate('team_props_401', retry);
      else console.error('Team props error:', err);
    }
    setTeamPropsLoading(null);
  }, [openPaywall, openSignupGate, refreshUserPreservingBalance, setShowVerifyPrompt, updateBalanceFromResponse]);

  const handleInsightUnlock = useCallback(async (
    kind: 'steam' | 'sharp' | 'dvp' | 'hcw',
    forecast: ForecastModalState | null,
    retry: () => void | Promise<void>,
  ) => {
    if (!forecast) return;
    if (!isLoggedIn()) {
      openSignupGate(`${kind}_insight`, retry);
      return;
    }

    const eventId = forecast.eventId || '';
    const league = forecast.league || '';
    const setLoading = kind === 'steam'
      ? setSteamInsightLoading
      : kind === 'sharp'
        ? setSharpInsightLoading
        : kind === 'dvp'
          ? setDvpInsightLoading
          : setHcwInsightLoading;

    setLoading(true);
    try {
      const data = kind === 'steam'
        ? await unlockSteamInsight(eventId, league)
        : kind === 'sharp'
          ? await unlockSharpInsight(eventId, league)
          : kind === 'dvp'
            ? await unlockDvpInsight(eventId, league)
            : await unlockHcwInsight(eventId, league);
      updateBalanceFromResponse(data);
      setInsightAvailability((prev) => ({ ...prev, [kind]: true }));
      if (kind === 'steam') {
        setSteamInsightData(data.insightData);
        setSteamInsightUnlocked(true);
      } else if (kind === 'sharp') {
        setSharpInsightData(data.insightData);
        setSharpInsightUnlocked(true);
      } else if (kind === 'dvp') {
        setDvpInsightData(data.insightData);
        setDvpInsightUnlocked(true);
      } else {
        setHcwInsightData(data.insightData);
        setHcwInsightUnlocked(true);
      }
      refreshUserPreservingBalance();
    } catch (err: any) {
      if (err.status === 403 && err.data?.needsVerification) setShowVerifyPrompt(true);
      else if (err.status === 402) openPaywall(`${kind}_insight`);
      else if (err.status === 401) openSignupGate(`${kind}_insight_401`, retry);
      else console.error(`${kind.toUpperCase()} insight error:`, err);
    }
    setLoading(false);
  }, [openPaywall, openSignupGate, refreshUserPreservingBalance, setShowVerifyPrompt, updateBalanceFromResponse]);

  const handlePlayerPropUnlock = useCallback(async (
    assetId: string,
    teamSide: 'home' | 'away',
    retry: () => void | Promise<void>,
  ) => {
    if (!isLoggedIn()) {
      openSignupGate('player_prop', retry);
      return;
    }
    setPlayerPropUnlocking(assetId);
    try {
      const data = await unlockPlayerProp(assetId);
      updateBalanceFromResponse(data);
      setPlayerPropsAssets((prev) => prev.map((prop) => (
        prop.assetId === assetId
          ? { ...prop, ...buildUnlockedPlayerPropPatch(data) }
          : prop
      )));
      refreshUserPreservingBalance();
    } catch (err: any) {
      if (err.status === 403 && err.data?.needsVerification) setShowVerifyPrompt(true);
      else if (err.status === 402) openPaywall('player_prop');
      else if (err.status === 401) openSignupGate('player_prop_401', retry);
      else console.error('Player prop unlock error:', err);
    }
    setPlayerPropUnlocking(null);
  }, [openPaywall, openSignupGate, refreshUserPreservingBalance, setShowVerifyPrompt, updateBalanceFromResponse]);

  return {
    teamPropsLoading,
    homePropsData,
    awayPropsData,
    gamePropsBreakdown,
    homePropsUnlocked,
    awayPropsUnlocked,
    steamInsightLoading,
    sharpInsightLoading,
    steamInsightData,
    sharpInsightData,
    steamInsightUnlocked,
    sharpInsightUnlocked,
    dvpInsightLoading,
    dvpInsightData,
    dvpInsightUnlocked,
    hcwInsightLoading,
    hcwInsightData,
    hcwInsightUnlocked,
    insightAvailability,
    perPlayerMode,
    playerPropsAssets,
    playerPropMarkets,
    featuredPlayers,
    playerPropsFallbackReason,
    playerPropUnlocking,
    notReadyRetrying,
    setNotReadyRetrying,
    setInsightAvailability,
    resetForecastUnlockState,
    applyUnlockedForecastState,
    applyPublicForecastState,
    loadPlayerPropsStatus,
    loadGamePropsBreakdown,
    primeUnlimitedForecast,
    handleTeamPropsClick,
    handleInsightUnlock,
    handlePlayerPropUnlock,
  };
}
