'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import { observer } from 'mobx-react-lite';
import React, { useEffect, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import { PlaySourceContextProvider } from '@/hooks/usePlaySource';
import { ContextType } from '@/logging/contextTypes';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { Clip } from '@/state/clipStore';
import {
  MORE_SONGS_PROFILE_TAB,
  MORE_SONGS_REMIXES_TAB,
  MORE_SONGS_SIMILAR_TAB,
  MORE_SONGS_TRENDING_TAB,
  REMIX_OPTIONS_BUTTON_CLASSNAME,
  REMIX_OPTIONS_CLASSNAME,
  TRENDING_PLAYLIST_ID,
} from '@/utils/constants';

import RemixOptions from '../song/RemixOptions';
import Remixes from '../song/Remixes';
import SongCardAlt from '../song/SongCardAlt';
import SpinnerSVG from '../svg/SpinnerSVG';
import Tabs from '../tab/Tabs';

const MoreSongsPanel = observer(({ clip }: { clip: Clip }) => {
  const { library, clips, queue, playbar, session } = useStores();

  const [selected, setSelected] = useState(MORE_SONGS_SIMILAR_TAB);
  const [profileClipsData, setProfileClipsData] = useState<Clip[] | null>(null);
  const [trendingClipsData, setTrendingClipsData] = useState<Clip[] | null>(
    null
  );
  const [similarClipsData, setSimilarClipsData] = useState<Clip[] | null>(null);
  const [remixCount, setRemixCount] = useState<number>(0);

  const [isProfileDataLoaded, setIsProfileDataLoaded] = useState(false);
  const [isTrendingDataLoaded, setIsTrendingDataLoaded] = useState(false);
  const [isSimilarDataLoaded, setIsSimilarDataLoaded] = useState(false);
  const [isRemixesLoaded, setIsRemixesLoaded] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  const hasOtherPublicSongs = !!profileClipsData?.length;
  const hasSimilarSongs = !!similarClipsData?.length;
  const hasRemixes = remixCount > 0;

  useEffect(() => {
    const loadTrendingClips = async () => {
      await fetchTrendingClips();
      setIsTrendingDataLoaded(true);
    };
    loadTrendingClips();
  }, []);

  useEffect(() => {
    const loadClipBasedPlaylists = async () => {
      setIsLoading(true);
      await fetchSimilarClips();
      setIsSimilarDataLoaded(true);
      await fetchProfileClips();
      setIsProfileDataLoaded(true);

      const count = session?.flags?.['clip-parent-populates-remix-sidebar']
        ? await clips.getDisplayableRemixesCount(clip.id)
        : await clips.getDirectChildrenCount(clip.id);
      setRemixCount(count);
      setIsRemixesLoaded(true);
      setIsLoading(false);
    };
    loadClipBasedPlaylists();
  }, [clip.id, session.flags]);

  useEffect(() => {
    if (!isLoading && isRemixesLoaded && hasRemixes) {
      setSelected(MORE_SONGS_REMIXES_TAB);
    } else if (!isLoading && isProfileDataLoaded && isTrendingDataLoaded) {
      if (!profileClipsData || profileClipsData?.length === 0) {
        setSelected(MORE_SONGS_TRENDING_TAB);
      }
    }
  }, [
    isLoading,
    isProfileDataLoaded,
    isTrendingDataLoaded,
    isRemixesLoaded,
    profileClipsData,
    hasRemixes,
    session.flags,
  ]);

  useEffect(() => {
    if (
      selected === MORE_SONGS_PROFILE_TAB &&
      isProfileDataLoaded &&
      profileClipsData
    ) {
      if (
        queue.contextId === clip.id &&
        queue.contextType === ContextType.Song
      ) {
        queue.setClips([clip, ...profileClipsData]);
        queue.setPendingClips([]);
      } else {
        queue.setPendingClips([clip, ...profileClipsData]);
      }
    }
    if (
      selected === MORE_SONGS_TRENDING_TAB &&
      isTrendingDataLoaded &&
      trendingClipsData
    ) {
      if (
        queue.contextId === clip.id &&
        queue.contextType === ContextType.Song
      ) {
        queue.setClips([clip, ...trendingClipsData]);
        queue.setPendingClips([]);
      } else {
        queue.setPendingClips([clip, ...trendingClipsData]);
      }
    }
    if (
      selected === MORE_SONGS_SIMILAR_TAB &&
      isSimilarDataLoaded &&
      similarClipsData
    ) {
      if (
        queue.contextId === clip.id &&
        queue.contextType === ContextType.Song
      ) {
        queue.setClips([clip, ...similarClipsData]);
        queue.setPendingClips([]);
      } else {
        queue.setPendingClips([clip, ...similarClipsData]);
      }
    }
  }, [
    selected,
    isProfileDataLoaded,
    isTrendingDataLoaded,
    isSimilarDataLoaded,
    profileClipsData,
    trendingClipsData,
    similarClipsData,
  ]);

  async function fetchTrendingClips() {
    try {
      await clips.loadPlaylist(TRENDING_PLAYLIST_ID);
      const newTrendingSongs = clips.playlistById[TRENDING_PLAYLIST_ID];

      // Add null check to prevent undefined error
      if (newTrendingSongs && newTrendingSongs.playlist_clips) {
        setTrendingClipsData(
          newTrendingSongs.playlist_clips.map((clip) => clip.clip)
        );
      } else {
        // Fallback to empty array if playlist data is not available
        setTrendingClipsData([]);
        console.warn('Trending playlist data not available');
      }
      setIsTrendingDataLoaded(true);
    } catch (error) {
      console.error('Error fetching trending clips:', error);
      setTrendingClipsData([]);
      setIsTrendingDataLoaded(true);
    }
  }

  async function fetchProfileClips() {
    try {
      setIsProfileDataLoaded(false);
      const { data } = (await library.apiClient.GET(
        `/api/profiles/{handle}/recent_clips`,
        {
          params: { path: { handle: clip.handle || '' } },
        }
      )) as any;

      if (data && data.clips) {
        const filteredClips = data.clips.filter((c: any) => c.id !== clip.id);
        clips.updateClips(filteredClips);
        setProfileClipsData(filteredClips);
        setIsProfileDataLoaded(true);
      }
    } catch (error) {
      console.error('Error fetching profile clips:', error);
      setProfileClipsData([]);
    }
  }

  async function fetchSimilarClips() {
    try {
      setIsSimilarDataLoaded(false);
      const { data } = (await library.apiClient.GET(`/api/clips/get_similar/`, {
        params: { query: { id: clip.id } },
      })) as any;
      if (data && data.similar_clips) {
        const filteredClips = data.similar_clips.filter(
          (c: any) => c.id !== clip.id
        );
        clips.updateClips(filteredClips);
        setSimilarClipsData(filteredClips);
        setIsSimilarDataLoaded(true);
      }
    } catch (error) {
      setSimilarClipsData([]);
    }
  }

  const header = (
    <MoreSongsHeader
      clip={clip}
      selected={selected}
      setSelected={setSelected}
      profileTab={MORE_SONGS_PROFILE_TAB}
      remixesTab={MORE_SONGS_REMIXES_TAB}
      hasOtherPublicSongs={hasOtherPublicSongs}
      hasSimilarSongs={hasSimilarSongs}
      showRemixesTab={!!hasRemixes}
      remixCount={remixCount}
    />
  );

  const showRemixesContent = selected === MORE_SONGS_REMIXES_TAB && hasRemixes;

  const panelClips: Clip[] =
    (selected === MORE_SONGS_TRENDING_TAB
      ? trendingClipsData || []
      : selected === MORE_SONGS_PROFILE_TAB
        ? profileClipsData
        : selected === MORE_SONGS_SIMILAR_TAB
          ? similarClipsData
          : selected === MORE_SONGS_REMIXES_TAB
            ? clips.directChildrenByClipId[clip.id]?.clips || []
            : []) || [];

  const queueContextType =
    selected === MORE_SONGS_PROFILE_TAB
      ? ContextType.SongRecommendationsProfile
      : selected === MORE_SONGS_TRENDING_TAB
        ? ContextType.SongRecommendationsTrending
        : selected === MORE_SONGS_SIMILAR_TAB
          ? ContextType.SongRecommendationsSimilar
          : selected === MORE_SONGS_REMIXES_TAB
            ? ContextType.SongRecommendationsRemixes
            : ContextType.Song;

  const queueContextId = clip.id;

  const [containerHeight, setContainerHeight] = useState(300);
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const updateHeight = () => {
      if (containerRef.current) {
        setContainerHeight(containerRef.current.offsetHeight);
      }
    };

    updateHeight();
    const resizeObserver = new ResizeObserver(updateHeight);
    if (containerRef.current) {
      resizeObserver.observe(containerRef.current);
    }

    return () => resizeObserver.disconnect();
  }, []);

  return (
    <PlaySourceContextProvider
      playSourceType='more_songs_panel'
      playSourceId={clip.id}
    >
      <div
        ref={containerRef}
        className={`flex h-full w-full flex-col overflow-x-hidden overflow-y-hidden py-2 pl-2 ${showRemixesContent ? 'bg-transparent' : 'bg-background-primary'} relative`}
        style={{
          backgroundImage: showRemixesContent
            ? 'radial-gradient(circle at left top, rgb(110, 61, 34) 15%, rgb(72, 46, 23) 34%, rgb(68 33 51) 55%, rgb(24, 24, 25) 73%)'
            : 'none',
          backgroundSize: 'cover, cover',
          backgroundPosition: 'center, center',
          backgroundBlendMode: 'overlay',
        }}
      >
        {isLoading ? (
          <div className='flex h-full w-full items-center justify-center'>
            <SpinnerSVG />
          </div>
        ) : showRemixesContent ? (
          <div className='relative flex h-full flex-col'>
            <div className='relative z-10'>{header}</div>

            <div className='relative z-10 flex-1 overflow-x-hidden overflow-y-auto'>
              <Remixes
                clip={clip}
                containerHeight={containerHeight}
                hideToggle={true}
                useGradientBackground={false}
              />
            </div>
          </div>
        ) : (
          <>
            {header}
            <div className='flex-1 overflow-x-hidden overflow-y-auto'>
              {panelClips.map((clip: Clip, index: number) => {
                const onPlay = () => {
                  if (playbar.clip?.id === clip.id) {
                    playbar.togglePlay();
                    return;
                  }
                  queue.setPlayContext({
                    contextType: queueContextType,
                    contextId: queueContextId,
                    currentIndex: index + 1, // offset the index since the SongPage clip is being prepended to the context
                    clips: [clip, ...panelClips],
                    pendingClips: [],
                  });
                  playbar.playClip(clip);
                };
                return (
                  <SongCardAlt
                    clip={clips.clipById[clip.id]}
                    key={clip.id}
                    onClick={onPlay}
                    contextType={queueContextType}
                    contextId={queueContextId}
                  />
                );
              })}
            </div>
          </>
        )}
      </div>
      <div
        className='relative sticky bottom-0 z-20 w-full border-t border-primary/10 bg-background-primary py-3'
        onClick={(e) => e.stopPropagation()}
      >
        <RemixOptions
          clip={clip}
          dropdownPosition='top'
          className={REMIX_OPTIONS_CLASSNAME}
          buttonClassName={twMerge(REMIX_OPTIONS_BUTTON_CLASSNAME, 'py-6')}
        />
      </div>
    </PlaySourceContextProvider>
  );
});

export default MoreSongsPanel;

const MoreSongsHeader = observer(
  ({
    clip,
    selected,
    setSelected,
    remixesTab,
    showRemixesTab,
    remixCount,
  }: {
    clip: Clip;
    selected: string;
    setSelected: React.Dispatch<React.SetStateAction<string>>;
    profileTab: string;
    remixesTab: string;
    hasOtherPublicSongs: boolean | null;
    hasSimilarSongs: boolean;
    showRemixesTab: boolean;
    remixCount: number;
  }) => {
    const isMobile = !useBreakpointMd();
    const [startTime, setStartTime] = useState<Date>(new Date());
    const [tabTimes, setTabTimes] = useState<{ [key: string]: number }>({
      profile: 0,
      trending: 0,
      similar: 0,
      remixes: 0,
    });

    const trackTimeOnTabSwitch = (newTab: string) => {
      const endTime = new Date();
      const duration = (endTime.getTime() - startTime.getTime()) / 1000;

      const updatedTimes = {
        ...tabTimes,
        [selected]: tabTimes[selected] + duration,
      };

      setTabTimes(updatedTimes);
      logWebUserEvent({
        actionName: 'MoreSongsTabSessionTimeClicked',
        context: {
          tab: selected,
          duration: tabTimes[selected] + duration,
          profile: clip.display_name,
          isMobile: isMobile,
        },
      });

      setStartTime(new Date());
      setSelected(newTab);
    };

    const tabs: string[] = [];
    const tabLabels = [];

    if (showRemixesTab) {
      tabs.push(remixesTab);
      tabLabels.push({ label: `Remixes (${remixCount})` });
    }

    tabs.push(MORE_SONGS_SIMILAR_TAB);
    tabLabels.push({ label: 'Similar' });

    tabs.push(MORE_SONGS_PROFILE_TAB);
    tabLabels.push({ label: `By ${clip.display_name}` });

    return (
      <div className='no-scrollbar w-full overflow-x-auto pr-2'>
        <Tabs
          tabs={tabLabels}
          onTabClick={(index: number) => {
            setSelected(tabs[index]);
            trackTimeOnTabSwitch(tabs[index]);
          }}
          selectedIndex={tabs.indexOf(selected)}
          textClass={'text-sm whitespace-nowrap'}
          className='inline-flex flex-nowrap'
        />
      </div>
    );
  }
);
