import { type SyntheticEvent, useCallback, useMemo, useState } from 'react';

import InputSearch from '@design-system/Inputs/Search';
import { GiphyFetch } from '@giphy/js-fetch-api';
import { type IGif } from '@giphy/js-types';
import { Grid } from '@giphy/react-components';
import { useDebounce } from '@hooks/useDebounce';
import { Stack, Typography, useTheme } from '@mui/material';

import PoweredByGiphyLogo from '../../../../../assets/poweredByGiphy.png';
import {
  CONTENT_HEIGHT,
  EMPTY_GIFS_RESULT,
  GIF_DEBOUNCE_MS,
  GIF_GRID_WIDTH,
  GIF_LIMIT,
  GIF_RATING,
} from '../../constants';

import { useGifPicker } from './GifPickerContext';

type GifPickerProps = {
  title?: string;
  noResultsMessage?: string;
  searchPlaceholder?: string;
  onGifSelect?: (gif: IGif) => void;
  onClose?: () => void;
};

type GifPickerContentProps = GifPickerProps & { apiKey: string };

const GifPickerContent = ({
  apiKey,
  title,
  noResultsMessage = 'No GIFs found',
  searchPlaceholder = 'Search',
  onGifSelect,
  onClose,
}: GifPickerContentProps) => {
  const theme = useTheme();

  const gf = useMemo(() => new GiphyFetch(apiKey), [apiKey]);

  const [query, setQuery] = useState('');
  const searchTerm = useDebounce(query, GIF_DEBOUNCE_MS);

  const handleQueryChange = useCallback((value: string) => {
    setQuery(value);
  }, []);

  const fetchGifs = useCallback(
    (term: string, offset: number) => {
      const request = term
        ? gf.search(term, { offset, limit: GIF_LIMIT, rating: GIF_RATING })
        : gf.trending({ offset, limit: GIF_LIMIT, rating: GIF_RATING });
      return request.catch(() => EMPTY_GIFS_RESULT);
    },
    [gf],
  );

  const fetchGifsForGrid = useCallback(
    (offset: number) => fetchGifs(searchTerm, offset),
    [fetchGifs, searchTerm],
  );

  const handleGifClick = useCallback(
    (gif: IGif, e: SyntheticEvent<HTMLElement>) => {
      e.preventDefault();
      onGifSelect?.(gif);
      onClose?.();
    },
    [onGifSelect, onClose],
  );

  return (
    <Stack
      sx={{
        minHeight: 0,
        flex: 1,
        px: '10px',
        py: '15px',
        gap: 1,
      }}
    >
      {title && (
        <Typography
          component="h2"
          fontWeight="fontWeightSemiBold"
          color={theme.palette.new.text.neutral.default}
        >
          {title}
        </Typography>
      )}
      <InputSearch
        value={query}
        onChange={handleQueryChange}
        placeholder={searchPlaceholder}
        autoFocus
        sx={{
          '& .MuiInputBase-root': {
            backgroundColor: theme.palette.new.background.layout.default,
            height: '40px',
          },
          '& .MuiInputBase-input': {
            fontSize: '14px',
          },
          '& .MuiInputAdornment-root svg': {
            width: 15,
            height: 15,
          },
        }}
      />
      <Stack sx={{ overflow: 'auto' }}>
        <img
          src={PoweredByGiphyLogo}
          alt="Powered by Giphy"
          style={{ marginTop: '12px', marginBottom: '12px', width: '150px' }}
        />
        <Grid
          hideAttribution
          noResultsMessage={<Typography>{noResultsMessage}</Typography>}
          width={GIF_GRID_WIDTH}
          onGifClick={handleGifClick}
          columns={4}
          borderRadius={0}
          key={searchTerm}
          fetchGifs={fetchGifsForGrid}
        />
      </Stack>
    </Stack>
  );
};

const GifPicker = (props: GifPickerProps) => {
  const { apiKey } = useGifPicker();

  if (!apiKey) {
    return (
      <Stack
        sx={{
          height: CONTENT_HEIGHT,
          alignItems: 'center',
          justifyContent: 'center',
          color: theme => theme.palette.new.text.neutral.lighter,
        }}
      >
        Wrap with GifPickerProvider to use the GIF tab.
      </Stack>
    );
  }

  return (
    <GifPickerContent
      apiKey={apiKey}
      {...props}
    />
  );
};

export default GifPicker;
