import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { Button, BUTTON_SIZE, BUTTON_TYPE, Input, THEME, Typography, TYPOGRAPHY_TYPE } from 'gdb-web-shared-components';
import { bem } from 'utils/bem';
import { Loading } from 'common-v2/types';
import { Modal, ModalContentProps } from 'common-v2/components';
import { SEditModal, BEM_CLASS } from './s-edit-modal';
import { Popper } from 'common/components/popper';
import { Recent, Loader, ListHeader, Suggestions, List } from './components';

interface EditModalProps {
  isOpened: boolean;
  loading: Loading;
  processing: Loading;
  onClose(): void;
  onApply(): void;
  title: string;
  addedNodes: React.ReactNode[];
  recentNodes: React.ReactNode[];
  suggestedNodes: React.ReactNode[];
  onAddAll(): void;
  searchValue: string;
  searchPlaceholder?: string;
  onSearchChange: React.ChangeEventHandler<HTMLInputElement>;
  clearSearch(): void;
  errorState: React.ReactElement;
  emptyState: React.ReactElement;
  listHeader: React.ReactElement;
  width: number;
  height: number;
}

const classes = bem(BEM_CLASS);

export const EditModal = React.memo(
  ({
    isOpened,
    loading,
    processing,
    onClose,
    onApply,
    title,
    onAddAll,
    searchValue,
    searchPlaceholder,
    onSearchChange,
    clearSearch,
    addedNodes,
    recentNodes,
    suggestedNodes,
    errorState,
    emptyState,
    listHeader,
    width,
    height,
  }: EditModalProps) => {
    const isApplying = processing === Loading.Started || processing === Loading.Finished;

    const isLoadingFailed = loading === Loading.Failed;

    const isNoItems = addedNodes.length === 0 && recentNodes.length === 0;

    const recentSection = useMemo(
      () => recentNodes.length > 0 && <Recent recentNodes={recentNodes} className={classes('recent-artists')} />,
      [recentNodes]
    );

    const listContent = useMemo(() => {
      switch (loading) {
        case Loading.Idle:
        case Loading.Started:
          return <Loader className={classes('loader')} />;
        case Loading.Failed:
          return <div className={classes('error')}>{errorState}</div>;
        case Loading.Finished:
          return (
            <div className={classes('list')}>
              <ListHeader
                content={listHeader}
                isDisabled={isApplying}
                onAssignAll={onAddAll}
                className={classes('list-header')}
              />
              {isNoItems ? (
                <div className={classes('empty')}>{emptyState}</div>
              ) : (
                <>
                  {recentSection}
                  <List className={classes('artists-list')}>{addedNodes}</List>
                </>
              )}
            </div>
          );
      }
    }, [addedNodes, emptyState, errorState, isApplying, isNoItems, listHeader, loading, onAddAll, recentSection]);

    const isLoading = [Loading.Idle, Loading.Started].some(loadingState => loading === loadingState);

    const inputRef = useRef<HTMLDivElement>(null);
    const [inputWidth, setInputWidth] = useState(0);
    const isSearchEmpty = searchValue.length === 0;
    useLayoutEffect(() => setInputWidth(inputRef?.current?.clientWidth || 0), [isSearchEmpty]);

    const renderContent = (props: ModalContentProps) => (
      <SEditModal width={width} height={height} data-selector="edit-modal">
        <header className={classes('header')} data-selector="edit-modal-header">
          <Typography className={classes('title')} data-selector="edit-modal-title" type={TYPOGRAPHY_TYPE.heading2}>
            {title}
          </Typography>
          <Button
            theme={THEME.light}
            type={BUTTON_TYPE.tertiary}
            size={BUTTON_SIZE.smallRound}
            icon="cross"
            onClick={props.closeModal}
            data-selector="edit-modal-close-button"
          />
        </header>
        <div className={classes('content')}>
          {!isLoadingFailed && (
            <Popper
              content={<Suggestions width={inputWidth} suggestedNodes={suggestedNodes} />}
              placement="bottom-start"
              visible={!isLoading && searchValue.length > 0}
              offset={[0, 5]}
              maxWidth="none"
              onClickOutside={clearSearch}
            >
              <div className={classes('input-container')} ref={inputRef} data-selector="edit-modal-search">
                <Input
                  inputClassName={classes('input')}
                  disabled={isApplying}
                  theme={THEME.light}
                  value={searchValue}
                  placeholder={searchPlaceholder}
                  onChange={onSearchChange}
                  isClearable={searchValue.length > 0}
                  onClearClick={clearSearch}
                  icon="search"
                />
              </div>
            </Popper>
          )}
          {listContent}
        </div>
        {!isLoadingFailed && (
          <footer className={classes('footer')}>
            <Button
              theme={THEME.light}
              className={classes('button')}
              disabled={isApplying}
              caption="Cancel"
              type={BUTTON_TYPE.secondary}
              onClick={props.closeModal}
              data-selector="edit-modal-cancel-button"
            />
            <Button
              theme={THEME.light}
              disabled={isApplying || loading === Loading.Started}
              className={classes('button')}
              caption={!isApplying ? 'Apply' : undefined}
              type={BUTTON_TYPE.primary}
              onClick={onApply}
              icon={isApplying ? 'ellipsis' : undefined}
              isLoading={processing === Loading.Started}
              data-selector="edit-modal-apply-button"
            />
          </footer>
        )}
      </SEditModal>
    );

    return <Modal isOpened={isOpened} renderContent={renderContent} onClose={onClose} />;
  }
);
