import { pick } from 'lodash-es';
import { useEffect, useRef, useState } from 'react';

import { useContextSelector } from '@/hooks/useContextSelector';
import {
  FilterIcon,
  RotateReverseIcon,
  SortIcon,
  TriangleDownIcon,
} from '@/icons';

import { ButtonVariant } from '../button/Button';
import { ContextMenuTrigger } from '../contextMenu/ContextMenu';
import StudioContext from '../studio/StudioContext';
import { StudioProjectManagementContext } from '../studio/StudioProjectManagementContext';
import { getAllUsedClipIds } from '../studio/selectors';
import SpinnerSVG from '../svg/SpinnerSVG';
import { Tooltip } from '../tooltip/Tooltip';
import {
  FilterButton,
  FilterDropdownButton,
  FilterMenuItem,
  FilterSectionWrapper,
  SortMenuItem,
} from './FilterElements';
import {
  setCoverOnly,
  setFromSpecificStudioProject,
  setFullSongOnly,
  setHideDisliked,
  setHideStems,
  setIncludeStudioProjectClips,
  setLikedOnly,
  setOnlyIds,
  setPersonaOnly,
  setPublicOnly,
  setSort,
  setUploadOnly,
} from './filterActions';
import { BooleanFilter, sortOptions } from './types';
import { ClipBrowserContext } from './useClipBrowser';

export default function StudioFilters() {
  const studioProjectId = useContextSelector(
    StudioProjectManagementContext,
    (context) => context.loadedProject?.id
  );
  const currentProjectClipsOnly = useContextSelector(
    ClipBrowserContext,
    (context) =>
      context.filters.fromStudioProject.presence === BooleanFilter.True &&
      context.filters.fromStudioProject.studioProjectId === studioProjectId
  );
  const anyProjectClips = useContextSelector(
    ClipBrowserContext,
    (context) =>
      context.filters.fromStudioProject.presence !== BooleanFilter.False &&
      !currentProjectClipsOnly
  );
  const likedOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.liked === BooleanFilter.True
  );
  const publicOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.public === BooleanFilter.True
  );
  const uploadOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.upload === BooleanFilter.True
  );
  const hideDisliked = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.disliked === BooleanFilter.False
  );
  const hideStems = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.stem.presence === BooleanFilter.False
  );
  const personaOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.persona.presence === BooleanFilter.True
  );
  const coverOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.cover.presence === BooleanFilter.True
  );
  const fullSongOnly = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.fullSong === BooleanFilter.True
  );
  const sort = useContextSelector(
    ClipBrowserContext,
    (context) => context.filters.sort
  );
  const setFilters = useContextSelector(
    ClipBrowserContext,
    (context) => context.setFilters
  );
  const refetch = useContextSelector(
    ClipBrowserContext,
    (context) => context.query.refetch
  );

  const filterCount = [
    anyProjectClips,
    currentProjectClipsOnly,
    likedOnly,
    publicOnly,
    uploadOnly,
    fullSongOnly,
    coverOnly,
    personaOnly,
    hideDisliked,
    hideStems,
  ].filter(Boolean).length;

  const fetching = useContextSelector(
    ClipBrowserContext,
    (context) => context.query.isFetching
  );

  const allArrangedClipIds = useContextSelector(StudioContext, (context) =>
    getAllUsedClipIds(context.state)
  );

  const [inProjectFilter, setInProjectFilter] = useState(false);
  useEffect(() => {
    if (inProjectFilter) {
      setFilters(setOnlyIds(allArrangedClipIds));
    } else {
      setFilters(setOnlyIds(null));
    }
  }, [inProjectFilter, allArrangedClipIds, setFilters]);

  const lastCurrentProjectClipsOnly = useRef(currentProjectClipsOnly);
  const lastProjectId = useRef(studioProjectId);
  useEffect(() => {
    if (
      lastCurrentProjectClipsOnly.current &&
      studioProjectId &&
      studioProjectId !== lastProjectId.current
    ) {
      setFilters(setFromSpecificStudioProject(studioProjectId));
    }
    lastCurrentProjectClipsOnly.current = currentProjectClipsOnly;
    lastProjectId.current = studioProjectId;
  }, [studioProjectId, currentProjectClipsOnly, setFilters]);

  return (
    <FilterSectionWrapper compact style={{ marginTop: 4 }}>
      <Tooltip label='Refresh' placement='top'>
        <FilterButton
          disabled={fetching}
          variant={ButtonVariant.Standard}
          icon={
            fetching ? (
              <SpinnerSVG className='h-4 w-4' />
            ) : (
              <RotateReverseIcon className='h-4 w-4' />
            )
          }
          onClick={() => {
            refetch();
          }}
        />
      </Tooltip>
      <ContextMenuTrigger
        ButtonComponent={(props) => (
          <FilterDropdownButton
            variant={ButtonVariant.Secondary}
            icon={FilterIcon}
            className='py-2 [&>span]:gap-1'
            {...props}
          >
            {filterCount > 0 && `(${filterCount})`}
            <TriangleDownIcon className='-mx-1 h-5 w-5' />
          </FilterDropdownButton>
        )}
        ContentsComponent={() => (
          <>
            <FilterMenuItem
              label='Edits From Any Project'
              onChange={() =>
                setFilters(setIncludeStudioProjectClips(!anyProjectClips))
              }
              value={anyProjectClips}
            />
            <FilterMenuItem
              label='Edits From Current Project'
              onChange={() =>
                currentProjectClipsOnly
                  ? setFilters(setIncludeStudioProjectClips(false))
                  : studioProjectId &&
                    setFilters(setFromSpecificStudioProject(studioProjectId))
              }
              value={currentProjectClipsOnly}
            />
            <FilterMenuItem
              label='Liked'
              onChange={() => setFilters(setLikedOnly(!likedOnly))}
              value={likedOnly}
            />
            <FilterMenuItem
              label='Public'
              onChange={() => setFilters(setPublicOnly(!publicOnly))}
              value={publicOnly}
            />
            <FilterMenuItem
              label='Uploads'
              onChange={() => setFilters(setUploadOnly(!uploadOnly))}
              value={uploadOnly}
            />
            <FilterMenuItem
              label='Full song'
              onChange={() => setFilters(setFullSongOnly(!fullSongOnly))}
              value={fullSongOnly}
            />
            <FilterMenuItem
              label='Cover'
              onChange={() => setFilters(setCoverOnly(!coverOnly))}
              value={coverOnly}
            />
            <FilterMenuItem
              label='Persona'
              onChange={() => setFilters(setPersonaOnly(!personaOnly))}
              value={personaOnly}
            />
            <FilterMenuItem
              label='Hide Disliked'
              onChange={() => setFilters(setHideDisliked(!hideDisliked))}
              value={hideDisliked}
            />
            <FilterMenuItem
              label='Hide Stems'
              onChange={() => setFilters(setHideStems(!hideStems))}
              value={hideStems}
            />
          </>
        )}
      />
      <ContextMenuTrigger
        ButtonComponent={(props) => (
          <FilterDropdownButton
            icon={SortIcon}
            className='py-2 [&>span]:gap-1'
            variant={ButtonVariant.Secondary}
            {...props}
          >
            <TriangleDownIcon className='-mx-1 h-5 w-5' />
          </FilterDropdownButton>
        )}
        ContentsComponent={() => (
          <>
            {sortOptions.map((option) => (
              <SortMenuItem
                key={option.label}
                label={option.label}
                onActivate={() =>
                  setFilters(setSort(pick(option, 'sortBy', 'sortDirection')))
                }
                active={
                  sort.sortBy === option.sortBy &&
                  sort.sortDirection === option.sortDirection
                }
              />
            ))}
          </>
        )}
      />

      <FilterButton
        style={{
          paddingTop: 8,
          paddingBottom: 8,
          paddingBlock: 8,
          height: 36,
        }}
        active={likedOnly}
        onClick={() => setFilters(setLikedOnly(!likedOnly))}
      >
        Liked
      </FilterButton>

      <Tooltip label='Clips in the current project'>
        <FilterButton
          style={{
            paddingTop: 8,
            paddingBottom: 8,
            paddingBlock: 8,
            height: 36,
          }}
          active={inProjectFilter}
          onClick={() => {
            setInProjectFilter(!inProjectFilter);
            if (currentProjectClipsOnly) {
              setFilters(setIncludeStudioProjectClips(true));
            }
          }}
        >
          Project
        </FilterButton>
      </Tooltip>

      <Tooltip label='Clips created in "edit" mode in this project'>
        <FilterButton
          style={{
            paddingTop: 8,
            paddingBottom: 8,
            paddingBlock: 8,
            height: 36,
          }}
          active={currentProjectClipsOnly}
          onClick={() => {
            if (inProjectFilter) {
              setInProjectFilter(false);
            }
            if (currentProjectClipsOnly) {
              setFilters(setIncludeStudioProjectClips(true));
            } else if (studioProjectId) {
              setFilters(setFromSpecificStudioProject(studioProjectId));
            }
          }}
        >
          Edits
        </FilterButton>
      </Tooltip>
    </FilterSectionWrapper>
  );
}
