import React, { Fragment, useEffect, useState } from 'react';
import cn from 'classnames';

import { theme, Loader } from '@veeqo/ui';
import useDropdown from 'hooks/useDropdown';
import { ViewTreeItem } from 'components/ui/SortableViews/SortableViews';

import composeViewChunks from './composeViewChunks';
import View from './View';
import {
  ViewType, ViewsClassNames, ViewHandlers, CommonViewPropTypes,
} from './types';

import {
  Col,
  Container,
  LeftControls,
  RightControls,
  Button,
  Glyph,
  SortableViews,
  Dropdown,
  Wrap,
  Tooltip,
  Info,
  Text,
  FixedViews,
  FixedView,
  LoaderContainer,
} from './styled';

type ViewsPropsType = CommonViewPropTypes & ViewHandlers & {
  viewsClassName?: string;
  e2eViewsClassName?: string;
  viewClassName?: string;
  e2eViewClassName?: string;
  views: ViewType[];
  fixedViews: ViewType[];
  sortedCustomViews: ViewType[];
  isLoading: boolean;
  isSortingDropdownEnabled: boolean;
  handleCreateCustomView: () => void; // via button
  handleSortingChange: (treeData: ViewTreeItem[]) => void;
};

const generateClassNames = (prefix?: string): ViewsClassNames => ({
  container: prefix ? `${prefix}-views-container` : undefined,
  controls: prefix ? `${prefix}-views-controls` : undefined,
  createButton: prefix ? `${prefix}-create-view-button` : undefined,
  reorderButton: prefix ? `${prefix}-reorder-views-button` : undefined,
  loader: prefix ? `${prefix}-views-loader` : undefined,
  reorderDropdown: prefix ? `${prefix}-reorder-views-dropdown` : undefined,
  fixedViews: prefix ? `${prefix}-fixed-views` : undefined,
  fixedView: prefix ? `${prefix}-fixed-view` : undefined,
});

const Views = ({
  viewsClassName,
  e2eViewsClassName,
  viewClassName,
  e2eViewClassName,
  views,
  fixedViews,
  sortedCustomViews,
  activeViewKey,
  includedFilters,
  hasUnsavedChanges,
  pageName,
  isLoading,
  isSortingDropdownEnabled = true,
  onSave,
  onDelete,
  handleDuplicateView,
  handleChangeActiveView,
  handleCreateCustomView,
  handleCreateCustomViewWithCurrentFilters,
  handleSortingChange,
  handleDiscardUnsavedChanges,
  handleSaveToCurrentView,
  handleSetDefault,
}: ViewsPropsType) => {
  const { shouldShowDropdown, toggleShouldShowDropdown, closeDropdown } = useDropdown();
  const classNames = generateClassNames(viewsClassName);
  const e2eClassNames = generateClassNames(e2eViewsClassName);
  const scrollBehavior = window.customViewsScrollBehavior || 'smooth';
  const isSortingDropdownEmpty = (
    isSortingDropdownEnabled
    && (!isLoading && sortedCustomViews.length === 0)
  );
  const isSortingDropdownDisabled = (
    isSortingDropdownEnabled
    && (isLoading || isSortingDropdownEmpty)
  );

  const [chunkIndex, setChunkIndex] = useState(0);
  const [chunks, setChunks] = useState(composeViewChunks({ views }));
  const [isNewElementVisible, setIsNewElementVisible] = useState(true);
  const isShowNextControlEnabled = chunkIndex < chunks.length - 1
    || (!isNewElementVisible && chunks.length > 1);
  const isShowPrevControlEnabled = chunkIndex > 0;

  const handleUpdateChunks = () => setChunks(composeViewChunks({ views }));
  const handleChunkIndexChange = (newChunkIndex: number, customChunks = chunks) => {
    const nextChunkKeys = customChunks[newChunkIndex].map((i) => i.key);
    const customViewElements = document.querySelectorAll<HTMLElement>('.veeqo-react-view');
    const nextChunkElements = Array.from(
      customViewElements.values(),
    ).filter((viewEl) => nextChunkKeys.includes(viewEl.dataset.viewKey || ''));

    const [firstEl] = nextChunkElements;
    if (firstEl) firstEl.scrollIntoView({ behavior: scrollBehavior, block: 'nearest', inline: 'start' });

    setChunkIndex(newChunkIndex);
    setIsNewElementVisible(true);
  };

  useEffect(() => {
    setChunks(composeViewChunks({ views }));
    // eslint-disable-next-line
  }, [activeViewKey]);

  useEffect(() => {
    const newChunks = composeViewChunks({ views });
    setChunks(newChunks);
    const lastChunkIndex = newChunks.length - 1;
    const isNewViewAdded = newChunks.length > chunks.length
      || (
        newChunks.length === chunks.length
        && newChunks[lastChunkIndex].length > chunks[lastChunkIndex].length
      );
    const isNewViewNotCopy = views.length > 0 ? !views[views.length - 1].label.includes('copy') : true;

    if (isNewViewAdded && isNewViewNotCopy) {
      handleChunkIndexChange(lastChunkIndex, newChunks);
    }

    if (!isNewViewNotCopy) setIsNewElementVisible(false);
    // eslint-disable-next-line
  }, [views]);

  const handleShowNextChunk = () => (
    isShowNextControlEnabled && !isLoading
      ? handleChunkIndexChange(chunkIndex + 1 === chunks.length ? chunkIndex : chunkIndex + 1)
      : null
  );
  const handleShowPrevChunk = () => (
    isShowPrevControlEnabled && !isLoading ? handleChunkIndexChange(chunkIndex - 1) : null
  );

  const getView = (view: ViewType) => (
    <Fragment key={view.key}>
      <View
        className={viewClassName}
        e2eClassName={e2eViewClassName}
        view={view}
        activeViewKey={activeViewKey}
        includedFilters={includedFilters}
        hasUnsavedChanges={hasUnsavedChanges}
        pageName={pageName}
        updateChunks={handleUpdateChunks}
        onSave={onSave}
        onDelete={onDelete}
        handleDuplicateView={handleDuplicateView}
        handleChangeActiveView={handleChangeActiveView}
        handleDiscardUnsavedChanges={handleDiscardUnsavedChanges}
        handleSaveToCurrentView={handleSaveToCurrentView}
        handleCreateCustomViewWithCurrentFilters={handleCreateCustomViewWithCurrentFilters}
        handleSetDefault={handleSetDefault}
      />
    </Fragment>
  );

  return (
    <Wrap>
      <LeftControls className={cn(classNames?.controls, e2eClassNames?.controls)}>
        <Tooltip text={pageName ? `Create a custom view of your ${pageName}` : 'Create new view'}>
          <Button
            className={cn(classNames?.createButton, e2eClassNames?.createButton)}
            onClick={!isLoading ? handleCreateCustomView : () => { }}
          >
            <Glyph name="add" color={!isLoading ? theme.colors.neutral.ink.base : theme.colors.neutral.grey.base} />
          </Button>
        </Tooltip>
        <Tooltip text={isSortingDropdownEmpty ? 'There are no custom views' : 'Reorder views'}>
          <Button
            className={cn(classNames?.reorderButton, e2eClassNames?.reorderButton)}
            onClick={isSortingDropdownDisabled ? () => { } : toggleShouldShowDropdown}
          >
            <Glyph name="reorder" color={isSortingDropdownDisabled ? theme.colors.neutral.grey.base : theme.colors.neutral.ink.base} />
          </Button>
        </Tooltip>
      </LeftControls>
      <RightControls>
        <Button onClick={!isShowPrevControlEnabled ? () => { } : handleShowPrevChunk}>
          <Glyph
            name="left-arrow"
            color={!isShowPrevControlEnabled
              ? theme.colors.neutral.grey.base
              : theme.colors.neutral.ink.base}
          />
        </Button>
        <Button onClick={!isShowNextControlEnabled ? () => { } : handleShowNextChunk}>
          <Glyph
            name="right-arrow"
            color={!isShowNextControlEnabled
              ? theme.colors.neutral.grey.base
              : theme.colors.neutral.ink.base}
          />
        </Button>
      </RightControls>
      <Container className={cn(classNames?.container, e2eClassNames?.container)}>
        {!isLoading ? (
          <>
            {fixedViews.map(getView)}
            {sortedCustomViews.map(getView)}
          </>
        ) : (
          <LoaderContainer>
            <Loader height={40} className={cn(classNames?.loader, e2eClassNames?.loader)} />
          </LoaderContainer>
        )}
      </Container>
      <Dropdown
        className={cn(classNames?.reorderDropdown, e2eClassNames?.reorderDropdown)}
        onClickAway={closeDropdown}
        shouldShowDropdown={shouldShowDropdown}
      >
        <Col>
          <FixedViews className={cn(classNames?.fixedViews, e2eClassNames?.fixedViews)}>
            <Text variant="subheadingSmall" margin="0 0 12px 0">Fixed views</Text>
            {fixedViews.map((view) => (
              <FixedView
                className={cn(classNames?.fixedView, e2eClassNames?.fixedView)}
                key={view.key}
                id={view.key}
                label={view.label}
              />
            ))}
          </FixedViews>
          <Info>
            <Glyph name="info" color={theme.colors.brand.blue.base} />
            <Text variant="bodySmall">
              Fixed views cannot be edited / deleted
            </Text>
          </Info>
          <SortableViews
            views={sortedCustomViews.map((view) => ({
              id: view.key,
              isDefault: view.default,
              ...view,
            }))}
            onChange={handleSortingChange}
          />
        </Col>
      </Dropdown>
    </Wrap>
  );
};

export default Views;
