'use client';

import { useCallback, useRef, useState } from 'react';
import { getForecast, getForecastPreview, getFreePickContent, isLoggedIn } from '@/lib/api';
import {
  toForecastModalState,
  toForecastPreviewModalState,
  type ForecastModalState,
} from '@/lib/forecast-modal';
import { trackConversion, trackEvent } from '@/lib/tracking';
import { isForecastNotReadyResponse } from '@/contracts/forecast-public';
import useForecastUnlockState, { resolveInsightAvailability } from '@/hooks/useForecastUnlockState';
import useForecastTransitionState from '@/hooks/useForecastTransitionState';
import type { SignupGateContext } from '@/components/forecast-page-types';

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

export default function useForecastModalController({
  user,
  pathname,
  markOwnedPick,
  openSignupGate,
  openPaywall,
  refreshUserPreservingBalance,
  updateBalanceFromResponse,
  setShowVerifyPrompt,
  onNavigateToForecasts,
}: UseForecastModalControllerArgs) {
  const [forecastLoading, setForecastLoading] = useState<string | null>(null);
  const activeForecastEventIdRef = useRef<string | null>(null);
  const forecastPrimeRequestRef = useRef(0);
  const unlockState = useForecastUnlockState({
    user,
    openSignupGate,
    openPaywall,
    refreshUserPreservingBalance,
    updateBalanceFromResponse,
    setShowVerifyPrompt,
  });
  const transitionState = useForecastTransitionState();

  const isCurrentRequest = useCallback((requestId: number, eventId: string) => (
    forecastPrimeRequestRef.current === requestId && activeForecastEventIdRef.current === eventId
  ), []);

  const openNotReadyForecast = useCallback((data: any, eventId: string, extras?: { isFreePick?: boolean }) => {
    activeForecastEventIdRef.current = eventId;
    transitionState.clearPendingTransitions();
    transitionState.setPreviewData(null);
    unlockState.resetForecastUnlockState();
    unlockState.setInsightAvailability(resolveInsightAvailability(data));
    transitionState.showForecastImmediately(toForecastModalState(data, eventId, extras));
  }, [transitionState, unlockState]);

  const applyForecastUpdateIfCurrent = useCallback((
    requestId: number,
    eventId: string,
    data: any,
    extras?: { isFreePick?: boolean },
  ) => {
    if (!isCurrentRequest(requestId, eventId)) {
      return;
    }

    const nextState = toForecastModalState(data, eventId, extras);
    transitionState.setPendingForecast((prev) => (prev?.eventId === eventId ? nextState : prev));
    transitionState.setForecast((prev) => (prev?.eventId === eventId ? nextState : prev));
  }, [isCurrentRequest, transitionState]);

  const openResolvedForecast = useCallback((
    requestId: number,
    eventId: string,
    league: string,
    data: any,
    extras?: { isFreePick?: boolean },
  ) => {
    unlockState.resetForecastUnlockState();
    transitionState.queueForecast(toForecastModalState(data, eventId, extras));
    unlockState.applyUnlockedForecastState(data);
    markOwnedPick(eventId);
    updateBalanceFromResponse(data);
    refreshUserPreservingBalance();
    void unlockState.loadPlayerPropsStatus(requestId, eventId, isCurrentRequest);
    void unlockState.loadGamePropsBreakdown(requestId, eventId, isCurrentRequest);
    void unlockState.primeUnlimitedForecast(eventId, league, data)
      .then((primedData) => {
        applyForecastUpdateIfCurrent(requestId, eventId, primedData, extras);
      })
      .catch((err) => {
        console.error(`${extras?.isFreePick ? 'Free pick' : 'Forecast'} priming error:`, err);
      });
  }, [
    applyForecastUpdateIfCurrent,
    isCurrentRequest,
    markOwnedPick,
    refreshUserPreservingBalance,
    transitionState,
    unlockState,
    updateBalanceFromResponse,
  ]);

  const handleFreePickClick = useCallback(async (eventId: string, league: string) => {
    const requestId = ++forecastPrimeRequestRef.current;
    activeForecastEventIdRef.current = eventId;
    setForecastLoading(eventId);
    try {
      if (isLoggedIn()) {
        const data = await getForecast(eventId, league);
        if (isForecastNotReadyResponse(data)) {
          openNotReadyForecast(data, eventId, { isFreePick: true });
          setForecastLoading(null);
          return;
        }
        openResolvedForecast(requestId, eventId, league, data, { isFreePick: true });
      } else {
        const data = await getFreePickContent();
        if (data.forecast) {
          transitionState.queueForecast({
            eventId: data.eventId,
            isFreePick: true,
            notReady: false,
            forecast: data.forecast,
            confidence: data.confidence ?? 0,
            homeTeam: data.homeTeam,
            awayTeam: data.awayTeam,
            homeShort: data.homeShort,
            awayShort: data.awayShort,
            league: data.league,
            alreadyOwned: false,
            odds: data.odds ?? null,
            openingLines: data.openingLines ?? null,
            modelLines: data.modelLines ?? null,
            compositeConfidence: data.compositeConfidence ?? null,
            forecastVersion: data.forecastVersion ?? null,
            staticCommit: data.staticCommit,
            generatedAt: data.generatedAt ?? null,
            lastRefreshAt: data.lastRefreshAt ?? null,
            lastRefreshType: data.lastRefreshType ?? null,
            materialChange: data.materialChange ?? null,
            insightAvailability: resolveInsightAvailability(data),
            unlockedInsights: [],
            unlockedInsightData: {},
            basemonSummary: data.basemonSummary ?? null,
            rieSignals: data.rieSignals ?? null,
            ragInsights: data.ragInsights ?? null,
            strategyId: data.strategyId ?? null,
            mlbPhaseContext: data.mlbPhaseContext ?? null,
            mlbMatchupContext: data.mlbMatchupContext ?? null,
            forecastBalance: data.forecastBalance ?? data.forecast_balance,
            forecast_balance: data.forecast_balance,
          });
          unlockState.resetForecastUnlockState();
          unlockState.applyPublicForecastState(data);
        }
      }
    } catch (err) {
      console.error('Free pick error:', err);
    }
    setForecastLoading(null);
  }, [openNotReadyForecast, openResolvedForecast, transitionState, unlockState]);

  const handleForecastClick = useCallback(async (eventId: string, league?: string) => {
    const requestId = ++forecastPrimeRequestRef.current;
    activeForecastEventIdRef.current = eventId;
    const authenticated = isLoggedIn();
    trackEvent('card_click', {
      eventId,
      league: league || null,
      loggedIn: authenticated,
    }, { immediate: true });

    if (!authenticated) {
      openSignupGate({ source: 'forecast_click', eventId, league: league || null }, () => handleForecastClick(eventId, league));
      return;
    }

    setForecastLoading(eventId);
    try {
      const data = await getForecast(eventId, league);
      if (isForecastNotReadyResponse(data)) {
        openNotReadyForecast(data, eventId);
        setForecastLoading(null);
        return;
      }

      trackEvent('forecast_unlock', {
        eventId,
        league: league || data.league || null,
        confidence: data.confidence,
        compositeConfidence: data.compositeConfidence,
      });
      trackConversion('forecast_unlock', { eventId, league: league || data.league || null });
      openResolvedForecast(requestId, eventId, league || data.league || '', data);
    } catch (err: any) {
      if (err.status === 403 && err.data?.needsVerification) {
        setShowVerifyPrompt(true);
      } else if (err.status === 402) {
        try {
          const preview = await getForecastPreview(eventId);
          transitionState.queuePreview(toForecastPreviewModalState(preview, eventId, league || ''));
        } catch {
          openPaywall('forecast_click');
        }
      } else if (err.status === 401) {
        openSignupGate({ source: 'forecast_click_401', eventId, league: league || null }, () => handleForecastClick(eventId, league));
      } else {
        console.error('Forecast error:', err);
      }
    }
    setForecastLoading(null);
  }, [openNotReadyForecast, openPaywall, openResolvedForecast, openSignupGate, setShowVerifyPrompt, transitionState]);

  const handleForecastPreviewClick = useCallback(async (eventId: string, league?: string) => {
    forecastPrimeRequestRef.current += 1;
    activeForecastEventIdRef.current = null;
    trackEvent('forecast_preview_click', {
      eventId,
      league: league || null,
      loggedIn: isLoggedIn(),
    }, { immediate: true });

    setForecastLoading(eventId);
    try {
      const preview = await getForecastPreview(eventId);
      unlockState.resetForecastUnlockState();
      transitionState.queuePreview(toForecastPreviewModalState(preview, eventId, league || ''));
    } catch (err) {
      console.error('Forecast preview error:', err);
      openSignupGate({ source: 'forecast_preview_click', eventId, league: league || null }, () => handleForecastPreviewClick(eventId, league));
    }
    setForecastLoading(null);
  }, [openSignupGate, transitionState, unlockState]);

  const handleTeamPropsClick = useCallback((team: 'home' | 'away'): Promise<void> => (
    unlockState.handleTeamPropsClick(transitionState.forecast, team, () => handleTeamPropsClick(team))
  ), [transitionState.forecast, unlockState]);

  const handleSteamInsightClick = useCallback((): Promise<void> => (
    unlockState.handleInsightUnlock('steam', transitionState.forecast, () => handleSteamInsightClick())
  ), [transitionState.forecast, unlockState]);

  const handleSharpInsightClick = useCallback((): Promise<void> => (
    unlockState.handleInsightUnlock('sharp', transitionState.forecast, () => handleSharpInsightClick())
  ), [transitionState.forecast, unlockState]);

  const handleDvpInsightClick = useCallback((): Promise<void> => (
    unlockState.handleInsightUnlock('dvp', transitionState.forecast, () => handleDvpInsightClick())
  ), [transitionState.forecast, unlockState]);

  const handleHcwInsightClick = useCallback((): Promise<void> => (
    unlockState.handleInsightUnlock('hcw', transitionState.forecast, () => handleHcwInsightClick())
  ), [transitionState.forecast, unlockState]);

  const handlePlayerPropUnlock = useCallback((assetId: string, teamSide: 'home' | 'away'): Promise<void> => (
    unlockState.handlePlayerPropUnlock(assetId, teamSide, () => handlePlayerPropUnlock(assetId, teamSide))
  ), [unlockState]);

  const handleRetryNotReadyForecast = useCallback(async () => {
    const forecast = transitionState.forecast;
    if (!forecast?.notReady || !forecast.eventId || !forecast.league) return;
    unlockState.setNotReadyRetrying(true);
    try {
      const data = await getForecast(forecast.eventId, forecast.league);
      if (isForecastNotReadyResponse(data)) {
        transitionState.showForecastImmediately(toForecastModalState(data, forecast.eventId, { isFreePick: forecast.isFreePick }));
        unlockState.setInsightAvailability(resolveInsightAvailability(data));
        return;
      }
      transitionState.showForecastImmediately(toForecastModalState(data, forecast.eventId, { isFreePick: forecast.isFreePick }));
      unlockState.applyUnlockedForecastState(data);
      updateBalanceFromResponse(data);
      refreshUserPreservingBalance();
      void unlockState.loadPlayerPropsStatus(forecastPrimeRequestRef.current, forecast.eventId, isCurrentRequest);
    } catch (err) {
      console.error('Not-ready retry error:', err);
    } finally {
      unlockState.setNotReadyRetrying(false);
    }
  }, [isCurrentRequest, refreshUserPreservingBalance, transitionState, unlockState, updateBalanceFromResponse]);

  const closeForecast = useCallback(() => {
    forecastPrimeRequestRef.current += 1;
    activeForecastEventIdRef.current = null;
    const wasFreePick = transitionState.forecast?.isFreePick;
    transitionState.closeForecast();
    if (wasFreePick && pathname !== '/forecasts') {
      onNavigateToForecasts();
    }
  }, [onNavigateToForecasts, pathname, transitionState]);

  const handlePreviewUnlock = useCallback(() => {
    transitionState.closePreview();
    openPaywall('forecast_preview');
  }, [openPaywall, transitionState]);

  return {
    forecastLoading,
    forecast: transitionState.forecast,
    previewData: transitionState.previewData,
    teamPropsLoading: unlockState.teamPropsLoading,
    homePropsData: unlockState.homePropsData,
    awayPropsData: unlockState.awayPropsData,
    gamePropsBreakdown: unlockState.gamePropsBreakdown,
    homePropsUnlocked: unlockState.homePropsUnlocked,
    awayPropsUnlocked: unlockState.awayPropsUnlocked,
    steamInsightLoading: unlockState.steamInsightLoading,
    sharpInsightLoading: unlockState.sharpInsightLoading,
    steamInsightData: unlockState.steamInsightData,
    sharpInsightData: unlockState.sharpInsightData,
    steamInsightUnlocked: unlockState.steamInsightUnlocked,
    sharpInsightUnlocked: unlockState.sharpInsightUnlocked,
    dvpInsightLoading: unlockState.dvpInsightLoading,
    dvpInsightData: unlockState.dvpInsightData,
    dvpInsightUnlocked: unlockState.dvpInsightUnlocked,
    hcwInsightLoading: unlockState.hcwInsightLoading,
    hcwInsightData: unlockState.hcwInsightData,
    hcwInsightUnlocked: unlockState.hcwInsightUnlocked,
    insightAvailability: unlockState.insightAvailability,
    flyingMathActive: transitionState.flyingMathActive,
    flyingMathOrigin: transitionState.flyingMathOrigin,
    pendingForecast: transitionState.pendingForecast,
    pendingPreviewData: transitionState.pendingPreviewData,
    perPlayerMode: unlockState.perPlayerMode,
    playerPropsAssets: unlockState.playerPropsAssets,
    playerPropMarkets: unlockState.playerPropMarkets,
    featuredPlayers: unlockState.featuredPlayers,
    playerPropsFallbackReason: unlockState.playerPropsFallbackReason,
    playerPropUnlocking: unlockState.playerPropUnlocking,
    notReadyRetrying: unlockState.notReadyRetrying,
    handleFlyingMathComplete: transitionState.handleFlyingMathComplete,
    handleFreePickClick,
    handleForecastClick,
    handleForecastPreviewClick,
    handleTeamPropsClick,
    handleSteamInsightClick,
    handleSharpInsightClick,
    handleDvpInsightClick,
    handleHcwInsightClick,
    handlePlayerPropUnlock,
    handleRetryNotReadyForecast,
    closeForecast,
    closePreview: transitionState.closePreview,
    handlePreviewUnlock,
  };
}
