import styled from '@emotion/styled';
import { useQuery } from '@tanstack/react-query';
import { observer } from 'mobx-react-lite';
import { useEffect, useMemo, useState } from 'react';
import { useDebounceValue } from 'usehooks-ts';

import { useStores } from '@/app/(root)/AppProviders';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  CheckboxIcon,
  CheckboxOutlineIcon,
  CoversIcon,
  FilterIcon,
  RecentPromptsIcon,
  SearchIcon,
  ThumbsUpIcon,
} from '@/icons';
import { isDisliked, isLiked } from '@/state/clipStore';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '../button/Button';
import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '../contextMenu/ContextMenu';
import SpinnerSVG from '../svg/SpinnerSVG';
import { Tooltip } from '../tooltip/Tooltip';
import EditV3LibrarySong from './EditV3LibrarySong';
import StudioContext from './StudioContext';
import StudioGenerateButton from './StudioGenerateButton';
import healEdits, { canHealSelection } from './actions/healEdits';
import { fetchLineage } from './fetchLineage';
import { getFocusedStudioClip } from './selectors';
import sortStudioClips from './sortStudioClips';
import useScrollMemory from './useScrollMemory';

const Wrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: stretch;
  gap: 10px;
  background-color: var(--color-background-secondary);
  height: 100%;
  border-radius: 10px;
  padding: 10px;
`;

const Filters = styled.div`
  display: flex;
  gap: 10px;
  height: 32px;
`;

const SectionTitle = styled.div`
  font-size: 14px;
`;

const AlternatesSectionWrapper = styled.div`
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: stretch;
  border-radius: 10px;
  background-color: var(--color-background-tertiary);
  padding: 10px;
  max-height: 250px;
`;

const ClipList = styled.div`
  display: grid;
  grid-template-rows: repeat(auto-fill, 60px);
  align-items: stretch;
  gap: 2px;
  overflow: auto;
  flex-grow: 1;
`;

export const AlternatesSection = ({ alternates }: { alternates: string[] }) => {
  const canHeal = useContextSelector(
    StudioContext,
    (context) =>
      getFocusedStudioClip(context.state) && canHealSelection(context.state)
  );
  const isPreviewing = useContextSelector(
    StudioContext,
    (context) => !!context.previewController.previewPackage
  );
  const stopPreviewing = useContextSelector(
    StudioContext,
    (context) => context.previewController.stopPreviewing
  );
  const setState = useContextSelector(
    StudioContext,
    (context) => context.setState
  );
  const clipsById = useContextSelector(
    StudioContext,
    (context) => context.clipsById
  );
  const mode = useContextSelector(StudioContext, (context) => context.mode);
  return (
    <AlternatesSectionWrapper>
      <SectionTitle>Alternates</SectionTitle>
      {!alternates.length ? (
        <div className='flex h-full w-full items-center justify-center'>
          Loading...
        </div>
      ) : (
        <ClipList>
          <ClipListContents clipIds={alternates} />
        </ClipList>
      )}
      <div className='flex items-center justify-between gap-2'>
        {canHeal || isPreviewing ? (
          <Button
            variant={ButtonVariant.Tertiary}
            shape={ButtonShape.Pill}
            icon={<RecentPromptsIcon className='h-4 w-4' />}
            onClick={() => {
              if (isPreviewing) {
                stopPreviewing();
              } else if (canHeal) {
                setState(healEdits(clipsById));
              }
            }}
          >
            {isPreviewing ? 'Stop Preview' : 'Original Audio'}
          </Button>
        ) : (
          <div />
        )}
        <div className='flex items-center gap-2'>
          {mode === 'edit' && (
            <StudioGenerateButton
              tooltipPlacement='top'
              eventTrigger='selection-interactions'
            />
          )}
        </div>
      </div>
    </AlternatesSectionWrapper>
  );
};

const ClipListContents = ({
  clipIds,
  refetch,
}: {
  clipIds: string[];
  refetch?: () => void;
}) => {
  const [draggedClipId, setDraggedClipId] = useState<string | null>(null);
  const reversedClipIds = useMemo(() => {
    return [...clipIds].reverse();
  }, [clipIds]);

  return (
    <>
      {reversedClipIds.map((clipId) => (
        <EditV3LibrarySong
          key={clipId}
          clipId={clipId}
          isDragging={draggedClipId === clipId}
          onDragStart={() => setDraggedClipId(clipId)}
          onDragEnd={() => setDraggedClipId(null)}
          onLikeChange={refetch}
          preventStreamingPlayback
        />
      ))}
    </>
  );
};

const FullClipList = ({
  clipList,
  refetch,
}: {
  clipList: string[];
  refetch?: () => void;
}) => {
  if (clipList) {
    return <ClipListContents clipIds={clipList} refetch={refetch} />;
  }
  return <div>Loading...</div>;
};

const SearchInputWrapper = styled.div`
  position: relative;
  border-radius: 100px;
  border: 1px solid var(--color-border-primary);
  input {
    background-color: transparent;
    border: none;
    padding: 10px;
    padding-left: 40px;
    width: 100%;
    height: 100%;
    border-radius: inherit;
  }
`;

const SearchInputIcon = styled.div`
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 35px;
`;

const SearchInput = ({
  value,
  onChange,
}: {
  value: string;
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}) => {
  return (
    <SearchInputWrapper>
      <SearchInputIcon>
        <SearchIcon className='h-5 w-5' />
      </SearchInputIcon>
      <input value={value} onChange={onChange} />
    </SearchInputWrapper>
  );
};

export default observer(function StudioLibrary() {
  const { session, clips: clipsStore, project } = useStores();
  const editClipId = useContextSelector(
    StudioContext,
    (context) => context.state.editClipId
  );
  const mode = useContextSelector(StudioContext, (context) => context.mode);
  const studioProjectId = useContextSelector(
    StudioContext,
    (context) => context.studioProjectId
  );
  const fullClipListQuery = useQuery({
    queryKey: [
      'main-clip-list-v2',
      mode === 'edit' ? editClipId : project.currentProjectId,
      project.filters.liked,
      project.filters.hide_disliked,
    ],
    queryFn: async () => {
      if (mode !== 'edit') {
        return project.clipIds;
      }
      if (!editClipId) return [];
      const result = await fetchLineage(session.apiClient, editClipId, true);
      return result.child_clips
        .filter(
          (c) =>
            ['CR', 'INF', 'CI', 'EX', 'ME', 'INT', 'OU', 'FA'].includes(
              c.relationship
            ) && c.clip.user_id === session.userId
        )
        .filter((c) => {
          const clip = clipsStore.clipById[c.clip.id] || c.clip;
          if (project.filters.hide_disliked && isDisliked(clip)) return false;
          if (project.filters.liked && !isLiked(clip)) return false;
          return true;
        })
        .sort((c1, c2) => sortStudioClips(c1.clip, c2.clip))
        .map((c) => c.clip.id);
    },
  });

  useEffect(() => {
    fullClipListQuery.refetch();
  }, [mode, project.clipIds, project.currentProjectId]);

  useEffect(() => {
    project.loadClips();
  }, [project.currentProjectId]);

  const [searchQuery, setSearchQuery] = useState('');
  const [debouncedSearchQuery] = useDebounceValue(searchQuery, 150);

  const filteredFullClipList = useMemo(() => {
    if (!searchQuery) {
      return fullClipListQuery.data || [];
    }
    return (
      fullClipListQuery.data?.filter((c) => {
        const clip = clipsStore.clipById[c];
        if (!clip) return false;
        const clipText = [
          clip.title?.toLowerCase() || '',
          clip.metadata.tags?.toLowerCase() || '',
          clip.metadata.negative_tags?.toLowerCase() || '',
          clip.metadata.prompt?.toLowerCase() || '',
          clip.metadata.gpt_description_prompt?.toLowerCase() || '',
        ].join(' ');
        return clipText.toLowerCase().includes(searchQuery.toLowerCase());
      }) || []
    );
  }, [fullClipListQuery.data, clipsStore.clipById, debouncedSearchQuery]);

  const scrollMemory = useScrollMemory(`studio-library-${studioProjectId}`);

  return (
    <Wrapper>
      <Filters>
        <ContextMenuTrigger
          placement='bottom-right'
          ButtonComponent={(props) => (
            <Button
              {...props}
              shape={ButtonShape.Pill}
              variant={ButtonVariant.Secondary}
              icon={<FilterIcon />}
            />
          )}
          ContentsComponent={observer(() => (
            <>
              {mode !== 'edit' && (
                <ContextMenuItem
                  keepMenusOpen
                  onClick={() =>
                    project.updateFilters({
                      hide_studio_clips: !project.filters.hide_studio_clips,
                    })
                  }
                  icon={
                    project.filters.hide_studio_clips ? (
                      <CheckboxIcon />
                    ) : (
                      <CheckboxOutlineIcon />
                    )
                  }
                >
                  Hide Clips from Studio & Edit Mode
                </ContextMenuItem>
              )}
              <ContextMenuItem
                keepMenusOpen
                onClick={() =>
                  project.updateFilters({
                    hide_disliked: !project.filters.hide_disliked,
                  })
                }
                icon={
                  project.filters.hide_disliked ? (
                    <CheckboxIcon />
                  ) : (
                    <CheckboxOutlineIcon />
                  )
                }
              >
                Hide Disliked
              </ContextMenuItem>
            </>
          ))}
        />
        <Button
          size={ButtonSize.Small}
          variant={
            project.filters.liked
              ? ButtonVariant.Primary
              : ButtonVariant.Secondary
          }
          className='flex h-full items-center justify-center truncate overflow-hidden py-0'
          icon={<ThumbsUpIcon className='h-4 w-4' />}
          shape={ButtonShape.Pill}
          onClick={() => {
            project.updateFilters({
              liked: !project.filters.liked,
            });
          }}
        >
          Liked
        </Button>
        <Tooltip label='Refresh'>
          <Button
            disabled={fullClipListQuery.isPending}
            size={ButtonSize.Small}
            variant={ButtonVariant.Secondary}
            className='flex h-full items-center justify-center truncate overflow-hidden py-0'
            icon={
              fullClipListQuery.isPending ? (
                <SpinnerSVG className='h-4 w-4' />
              ) : (
                <CoversIcon className='h-4 w-4' />
              )
            }
            shape={ButtonShape.Pill}
            onClick={() => {
              fullClipListQuery.refetch();
            }}
          />
        </Tooltip>
        <SearchInput
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
        />
      </Filters>
      {filteredFullClipList.length > 0 && (
        <ClipList ref={scrollMemory}>
          <FullClipList
            clipList={filteredFullClipList}
            refetch={fullClipListQuery.refetch}
          />
        </ClipList>
      )}
    </Wrapper>
  );
});
