'use client';

import { useMessages } from '@ably/chat/react';
import { useGateValue } from '@statsig/react-bindings';
import { useQuery } from '@tanstack/react-query';
import { observer } from 'mobx-react-lite';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { useLocalStorage } from 'usehooks-ts';

import { useStores } from '@/app/(root)/AppProviders';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { CollapseContentIcon, ExpandContentIcon } from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';

import { useFullscreen } from '../../../hooks/useFullscreen';
import { FloatingVoteIcon, useFloatingIcons } from './FloatingVoteIcon';
import LiveChat from './LiveChat';
import LiveRadioAblyProvider from './LiveRadioAblyProvider';
import { LiveRadioContext } from './LiveRadioProvider';
import LivingRadioBackgroundVideo from './LivingRadioBackgroundVideo';
import MainRadioBanner from './MainRadioBanner';
import RadioTopBar from './RadioTopBar';
import { VoteMessageListener } from './VoteMessageListener';
import { VOTE_STATUS_REFETCH_INTERVAL } from './constants';
import { STATION_ID } from './constants';
import { VoteMessageMetadata, VoteStatus } from './interfaces';

// Component to load historical messages
const HistoricalMessagesLoader = ({
  onMessagesLoaded,
  onLoadingComplete,
}: {
  onMessagesLoaded: (messages: any[]) => void;
  onLoadingComplete: () => void;
}) => {
  const [hasLoadedHistory, setHasLoadedHistory] = useState(false);

  const { historyBeforeSubscribe } = useMessages({
    listener: () => {},
  });

  useEffect(() => {
    if (historyBeforeSubscribe && !hasLoadedHistory) {
      historyBeforeSubscribe({ limit: 50 })
        .then((result) => {
          if (result && result.items) {
            // Reverse the messages to show oldest first
            const historicalMessages = result.items.reverse();
            onMessagesLoaded(historicalMessages);
            setHasLoadedHistory(true);
          }
          onLoadingComplete();
        })
        .catch(() => {
          // Do nothing
        });
    }
  }, [
    historyBeforeSubscribe,
    hasLoadedHistory,
    onMessagesLoaded,
    onLoadingComplete,
  ]);

  return null; // This component doesn't render anything
};

const LivingRadioPage = observer(() => {
  const backgroundRef = useRef<HTMLDivElement>(null);
  const { session } = useStores();
  const {
    setIsLiveRadio,
    isPlaying,
    isLoading,
    currentSong,
    volume,
    setVolume,
    togglePlay,
  } = useContext(LiveRadioContext);

  // Use the floating icons hook
  const { floatingIcons, addFloatingIcon, removeFloatingIcon } =
    useFloatingIcons();

  // Use the fullscreen hook
  const { isFullscreen, supportsFullscreen, enterFullscreen, exitFullscreen } =
    useFullscreen(backgroundRef);

  // Living radio state - individual useState hooks
  const [voteStatus, setVoteStatus] = useState<VoteStatus | null>(null);
  const [isVoting, setIsVoting] = useState<boolean>(false);

  // Banner collapsed states
  const [isMainBannerCollapsed, setIsMainBannerCollapsed] =
    useState<boolean>(false);
  const [isChatBannerCollapsed, setIsChatBannerCollapsed] =
    useState<boolean>(true); // Default to closed, will be updated based on screen size

  // Track vote button positions for floating animations
  const [voteButtonPositions, setVoteButtonPositions] = useState<{
    [key: number]: DOMRect;
  }>({});

  // Track all chat messages
  const [chatMessages, setChatMessages] = useState<any[]>([]);
  const [isChatHistoryLoading, setIsChatHistoryLoading] = useState(true);

  // Viewport guard: below desktop width AND too short or narrow to fit both (main and chat) banners
  const shouldAutoCollapse = () =>
    window.innerWidth < 1280 &&
    (window.innerHeight < 750 || window.innerWidth < 370);

  // Initialize living radio
  useEffect(() => {
    setIsLiveRadio(true);
  }, [setIsLiveRadio]);

  // Log page view on mount - wait for session to be fully loaded to avoid duplicate events
  useEffect(() => {
    if (!session.sessionIsLoaded) return;

    logWebUserEvent({
      actionName: 'LivingRadioPageViewed',
      principalObjectType: 'livingRadioPage',
      principalObjectValue: STATION_ID,
      context: {
        userId: session.user?.id,
        stationId: STATION_ID,
        isAuthenticated: !!session.user,
      },
    });
  }, [session.sessionIsLoaded, STATION_ID, session.user]);

  // Track user votes per session using localStorage
  const [userVotes, setUserVotes] = useLocalStorage<Record<string, number>>(
    'living-radio-votes',
    {}
  );

  // API function for vote status only
  const fetchVoteStatus = useCallback(async (): Promise<VoteStatus> => {
    const { data, error } = await session.apiClient.GET(
      '/api/living_radio/{station_id}/vote-status',
      {
        params: { path: { station_id: STATION_ID } },
      }
    );
    if (error) {
      throw new Error('Failed to fetch vote status');
    }
    return (
      data || {
        styles: [],
        votes: [],
        vote_session_uuid: '',
        vote_closed: false,
        winning_style: '',
      }
    );
  }, [session.apiClient, STATION_ID]);

  // Query for vote status
  const { data: voteStatusData, refetch: refetchVoteStatus } = useQuery({
    queryKey: ['livingRadio', 'voteStatus'],
    queryFn: fetchVoteStatus,
    refetchInterval: VOTE_STATUS_REFETCH_INTERVAL,
    refetchIntervalInBackground: true,
  });

  // Update living radio state when data changes
  useEffect(() => {
    if (voteStatusData) {
      setVoteStatus(voteStatusData);
    }
  }, [voteStatusData]);

  const handleVolumeChange = useCallback(
    (newVolume: number) => {
      const clampedVolume = Math.max(0, Math.min(100, newVolume));
      setVolume(clampedVolume);
    },
    [setVolume]
  );

  // Handle spacebar press to toggle play/pause
  useEffect(() => {
    const handleKeydown = (event: KeyboardEvent) => {
      // Only trigger if spacebar is pressed and user is not typing in an input field
      if (
        event.code === 'Space' &&
        !['INPUT', 'TEXTAREA', 'SELECT'].includes(
          (event.target as HTMLElement)?.tagName
        )
      ) {
        event.preventDefault(); // Prevent page scrolling
        togglePlay();
      }
    };

    document.addEventListener('keydown', handleKeydown);

    return () => {
      document.removeEventListener('keydown', handleKeydown);
    };
  }, [togglePlay]);

  // Banner state handlers
  const handleMainBannerChange = useCallback((collapsed: boolean) => {
    setIsMainBannerCollapsed(collapsed);
    // On mobile/tablet, only collapse chat if there isn't enough vertical space
    if (!collapsed && shouldAutoCollapse()) {
      setIsChatBannerCollapsed(true);
    }
  }, []);

  const handleChatBannerChange = useCallback((collapsed: boolean) => {
    setIsChatBannerCollapsed(collapsed);
    // On mobile/tablet, only collapse main banner if there isn't enough vertical space
    if (!collapsed && shouldAutoCollapse()) {
      setIsMainBannerCollapsed(true);
    }
  }, []);

  // Handle vote messages from chat
  const handleVoteMessage = useCallback(
    (metadata: VoteMessageMetadata) => {
      if (!voteStatus || metadata.styleIndex === undefined) return;

      // Ignore vote messages from the current user to prevent duplicate optimistic updates
      if (metadata.userId === session.user?.id) {
        return;
      }

      // Update vote counts optimistically based on vote messages
      const newVotes = [...voteStatus.votes];

      // If switching votes, decrement the previous style
      if (
        metadata.isSwitching &&
        metadata.previousStyleIndex !== undefined &&
        metadata.previousStyleIndex !== null
      ) {
        newVotes[metadata.previousStyleIndex] = Math.max(
          0,
          newVotes[metadata.previousStyleIndex] - 1
        );
      }

      // Increment the new style
      newVotes[metadata.styleIndex] = newVotes[metadata.styleIndex] + 1;

      // Update the vote status with new counts
      setVoteStatus({
        ...voteStatus,
        votes: newVotes,
      });
    },
    [voteStatus, session.user?.id]
  );

  // Update vote button positions callback
  const updateVoteButtonPositions = useCallback(
    (positions: { [key: number]: DOMRect }) => {
      setVoteButtonPositions(positions);
    },
    []
  );

  // Set initial chat state based on screen size
  useEffect(() => {
    if (!shouldAutoCollapse()) {
      setIsChatBannerCollapsed(false);
    }
  }, []); // Run only once on mount

  // Callback for when user votes
  const handleUserVote = useCallback(
    (profileUrl: string, styleIndex: number, buttonRect: DOMRect) => {
      addFloatingIcon(profileUrl, styleIndex, buttonRect);
    },
    [addFloatingIcon]
  );

  // Callback to handle loaded historical messages
  const handleHistoricalMessagesLoaded = useCallback((messages: any[]) => {
    setChatMessages((prev) => {
      // Prepend historical messages to the beginning, avoiding duplicates
      const existingIds = new Set(prev.map((msg) => msg.id));
      const newHistoricalMessages = messages.filter(
        (msg) => !existingIds.has(msg.id)
      );
      return [...newHistoricalMessages, ...prev];
    });
  }, []);

  const shouldShowChat = useGateValue('living-radio-chat');

  // Set loading to false if historical messages fails or is empty
  useEffect(() => {
    // Set a timeout to ensure loading state doesn't persist forever
    const timeout = setTimeout(() => {
      setIsChatHistoryLoading(false);
    }, 5000);

    return () => clearTimeout(timeout);
  }, []);

  return (
    <LiveRadioAblyProvider stationId={STATION_ID}>
      {/* Load historical messages on mount */}
      <HistoricalMessagesLoader
        onMessagesLoaded={handleHistoricalMessagesLoaded}
        onLoadingComplete={() => setIsChatHistoryLoading(false)}
      />

      {/* Always-active vote message listener for floating icons */}
      <VoteMessageListener
        onVoteMessage={handleVoteMessage}
        voteButtonPositions={voteButtonPositions}
        onNewMessage={(message) =>
          setChatMessages((prev) => {
            const newMessages = [...prev, message];
            // Keep only the most recent 500 messages if over 1000
            if (newMessages.length > 1000) {
              return newMessages.slice(-500);
            }
            return newMessages;
          })
        }
        currentUserId={session.user?.id || null}
      />

      {/* Floating vote icons */}
      <FloatingVoteIcon
        icons={floatingIcons}
        onAnimationComplete={removeFloatingIcon}
      />

      <div className='relative flex h-[calc(100dvh-100px-env(safe-area-inset-bottom,0px))] w-full touch-none flex-col bg-background-primary p-0 supports-[height:100dvh]:h-[calc(100dvh-100px-env(safe-area-inset-bottom,0px))] supports-[height:100svh]:h-[calc(100svh-100px-env(safe-area-inset-bottom,0px))] md:h-screen md:p-4'>
        {/* Top bar with logo, search and create functionality */}
        <RadioTopBar className='relative top-0 right-0 mb-2 w-full max-md:hidden' />
        {/* Background box with video */}
        <div
          ref={backgroundRef}
          className={`w-full flex-1 rounded-none ${isFullscreen ? '' : 'md:rounded-[24px]'} relative flex flex-col items-center justify-center overflow-hidden`}
        >
          {/* Background video */}
          <LivingRadioBackgroundVideo />

          {/* Overlay for better text readability */}
          <div className='fixed inset-0 h-[calc(100dvh-50px-env(safe-area-inset-bottom,0px))] bg-linear-to-b from-black/15 via-black/25 via-60% to-black md:absolute md:h-screen md:bg-[radial-gradient(ellipse_at_center,transparent_0%,rgba(0,0,0,0.2)_50%,rgba(0,0,0,0.6)_100%)]' />

          {/* Floating expand/collapse button */}
          {supportsFullscreen && (
            <div className='absolute top-4 right-4 z-20'>
              <Button
                onClick={isFullscreen ? exitFullscreen : enterFullscreen}
                variant={ButtonVariant.Tertiary}
                size={ButtonSize.Small}
                shape={ButtonShape.Pill}
                aspectSquare={true}
                icon={isFullscreen ? CollapseContentIcon : ExpandContentIcon}
                aria-label={
                  isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'
                }
                className='bg-black/20! text-white! backdrop-blur-sm hover:bg-black/40!'
              />
            </div>
          )}

          {/* Main content */}
          {/* Floating Banners Container - responsive flex layout */}
          <div className='absolute right-2 bottom-4 left-2 pb-[calc(env(safe-area-inset-bottom,0px)+4px)] md:right-6 md:bottom-6 md:left-6'>
            <div className='flex max-h-[calc(100vh-env(safe-area-inset-bottom,0px))] flex-col justify-start gap-4 overflow-y-auto md:max-h-none xl:flex-row xl:items-end'>
              {/* Main Radio Banner */}
              <MainRadioBanner
                isCollapsed={isMainBannerCollapsed}
                onCollapsedChange={handleMainBannerChange}
                currentSong={currentSong}
                voteStatus={voteStatus}
                isPlaying={isPlaying}
                isLoading={isLoading}
                volume={volume}
                isVoting={isVoting}
                userVotes={userVotes}
                onTogglePlay={togglePlay}
                onVolumeChange={handleVolumeChange}
                onRefetchVoteStatus={refetchVoteStatus}
                onSetVoteStatus={setVoteStatus}
                onSetUserVotes={setUserVotes}
                onSetIsVoting={setIsVoting}
                onUpdateVoteButtonPositions={updateVoteButtonPositions}
                onUserVote={handleUserVote}
                stationId={STATION_ID}
                className='w-full touch-none rounded-[18px] xl:w-[650px] xl:shrink-0'
              />

              {/* Chat Component - responsive, visible on all screen sizes */}
              {shouldShowChat && (
                <LiveChat
                  isCollapsed={isChatBannerCollapsed}
                  onCollapsedChange={handleChatBannerChange}
                  className='w-full touch-none rounded-[18px] xl:max-w-[650px] xl:min-w-[300px] xl:flex-1'
                  messages={chatMessages}
                  stationId={STATION_ID}
                  isLoading={isChatHistoryLoading}
                />
              )}
            </div>
          </div>
        </div>
      </div>
    </LiveRadioAblyProvider>
  );
});

export default LivingRadioPage;
