import { useCallback, useEffect, useRef, useState, useTransition } from 'react';

import type { UserRosterArtistsResponse } from '~/lib/songwhipApi/types';
import type { FC } from 'react';

import Box from '~/src/components/Box';
import FadeOnMount from '~/src/components/FadeOnMount';
import ListItem from '~/src/components/ListItem';
import Loading from '~/src/components/Loading';
import { useAppAlert } from '~/src/components/NextApp/lib/CoreUi';
import SearchTextInput from '~/src/components/SearchTextInput';
import Text from '~/src/components/Text';
import { useI18n } from '~/src/lib/i18n';
import { useAppRouter } from '~/src/lib/router2';
import { getCatalogArtistsApi } from '~/src/lib/songwhipApi/users/getCatalogArtistsApi';
import { searchCatalogArtistsApi } from '~/src/lib/songwhipApi/users/searchCatalogArtistsApi';
import { useTracker } from '~/src/lib/tracker/useTracker';
import isTruthy from '~/src/lib/utils/isTruthy';
import onceIdle from '~/src/lib/utils/onceIdle';

export type RosterArtist = UserRosterArtistsResponse['items'][number];

type ArtistSearchProps = {
  userId: number;
  onSelectArtist(artist: RosterArtist): void | Promise<void>;
};

export const ArtistSearch: FC<ArtistSearchProps> = ({
  userId,
  onSelectArtist,
}) => {
  const searchRef = useRef<HTMLInputElement>(null);

  const { t } = useI18n('create');
  const { trackEvent } = useTracker();
  const router = useAppRouter();
  const appAlert = useAppAlert();
  const searchQuery = router.getAsQuery().q;

  const [suggestedArtists, setSuggestedArtists] = useState<RosterArtist[]>();
  const [artists, setArtists] = useState<RosterArtist[]>();

  const [isSuggestionsLoading, setIsSuggestionsLoading] = useState(false);
  const [isArtistsLoading, setIsArtistsLoading] = useState(false);
  const [selectedArtistId, setSelectedArtistId] = useState<string>();
  const [, startTransition] = useTransition();

  const isLoading = isSuggestionsLoading || isArtistsLoading;

  useEffect(() => {
    // load suggestions only once, only when search query is empty
    if (searchQuery || suggestedArtists !== undefined) return;

    setIsSuggestionsLoading(true);

    getCatalogArtistsApi({
      userId,
      limit: 10,
    })
      .then(({ items }) => {
        setSuggestedArtists(items);
      })
      .finally(() => {
        setIsSuggestionsLoading(false);

        // make sure loading is false before focusing
        onceIdle(() => {
          searchRef.current?.focus();
        });
      });
  }, [searchQuery]);

  useEffect(() => {
    if (searchQuery) {
      setIsArtistsLoading(true);

      searchCatalogArtistsApi({
        userId,
        term: searchQuery,
      })
        .then(({ items }) => {
          setArtists(items);
        })
        .finally(() => {
          setIsArtistsLoading(false);

          // make sure loading is false before focusing
          onceIdle(() => {
            searchRef.current?.focus();
          });
        });
    } else {
      // reset artists to avoid showing old results
      // and flickering on switching between search and suggestions
      setArtists(undefined);
    }
  }, [searchQuery]);

  const toArtistListItem = (artist: RosterArtist) => {
    const { sourceUrl } = artist;
    const isArtistSelected = selectedArtistId === artist.id;

    if (!sourceUrl) return;

    return (
      <ListItem
        testId="catalogItem"
        key={artist.id}
        title={artist.name}
        image={artist.image ?? undefined}
        imageSize="4rem"
        height="6rem"
        isDisabled={!!selectedArtistId}
        onClick={async () => {
          // Avoid showing loading and disabled states
          // if artist data is already being fetched
          startTransition(() => {
            setSelectedArtistId(artist.id);
          });

          try {
            await onSelectArtist(artist);
          } catch {
            appAlert({
              content: t('artist.selectingError'),
            });

            setSelectedArtistId(undefined);
          }
        }}
        renderAfter={
          isArtistSelected ? () => <Loading size="2.2rem" /> : undefined
        }
      />
    );
  };

  const renderSuggestions = (() => {
    const items = suggestedArtists?.map(toArtistListItem).filter(isTruthy);

    if (!items) return <></>;
    else if (items.length === 0) {
      return (
        <Text centered isParagraph color="#ccc" size="1.5rem">
          {t('artist.noSuggestions')}
        </Text>
      );
    }

    return (
      <>
        <Text tag="h4" size="1.5rem" margin="0 0 1.15rem 0" color="#999" isBold>
          {t('artist.suggestionsTitle')}
        </Text>
        {items}
      </>
    );
  })();

  const renderSearchItems = (() => {
    const items = artists?.map(toArtistListItem).filter(isTruthy);

    if (!items) return <></>;
    else if (items.length === 0) {
      return (
        <Text centered isParagraph color="#ccc" size="1.5rem">
          {t('noResults')}
        </Text>
      );
    }

    return items;
  })();

  return (
    <FadeOnMount>
      <Box maxWidth="48rem" width="100%">
        <SearchTextInput
          inputRef={searchRef}
          isLoading={isLoading}
          isDisabled={isLoading}
          testId="searchInput"
          height="5rem"
          placeholder={
            isSuggestionsLoading
              ? t('artist.fetchingSuggestions')
              : t('artist.searchPlaceholder')
          }
          defaultValue={searchQuery}
          onInputEnd={useCallback(({ value }) => {
            router.setQuery({
              q: value || undefined,
            });

            trackEvent({
              type: 'search',
              id: 'create-artist-page:search-catalog-artists',
              term: value,
            });
          }, [])}
          autoFocus
          centerText
        />
        <Box margin="3rem 0 0">
          {searchQuery ? renderSearchItems : renderSuggestions}
        </Box>
      </Box>
    </FadeOnMount>
  );
};
