import PropTypes, { string } from 'prop-types';
import moment from 'moment';
import { ThemeProvider } from 'styled-components';
import React, { useState, Fragment, useEffect } from 'react';
import { isEmpty } from 'lodash';

import { ORDER_TYPE } from './constants';

import {
  NestedListContainer,
  RowsContainer,
  BorderedContainer,
  RowContainer,
  Container,
  FixedRowContainer,
  FixedRowsContainer,
  PaginatorContainer,
  GlobalContainer,
} from './styledComponents';
import HeaderRow from './components/HeaderRow/HeaderRow';
import EmptyState from './components/EmptyState';
import LoadingState from './components/LoadingState/LoadingStateDisplay';

import useInteractDataRowAndGraph from './customHook/useInteractDataRowAndGraph';

import Row from './components/Row/Row';

import { getTheme } from '../utils/theme';

import { Props } from './interface';
import Paginator from '../Paginator';

const NestedList = (props: Props): JSX.Element => {
  const {
    theme,
    headers,
    modalHeaders,
    data,
    fixedRowsData,
    isLoading,
    isExpandable,
    defaultOrderBy,
    defaultOrderType,
    customMultipleOrder,
    minWidth,
    customModalIcon,
    labelEmptyState,
    iconEmptyState,
    iconSizeEmptyState,
    modalTitle,
    labelModalEmptyState,
    graphEmptyStateLabel,
    languageCode,
    hasNestedData,
    hasPagination,
    maxPerPageOptions,
    hideAllPerPageOption,
    customSortProperty,
    customSortFunc,
    customNestedContentPadding,
    currentPage,
    setCurrentPage,
    maxPerPage,
    setMaxPerPage,
    customContentHeight,
  } = props;

  const updatedTheme = getTheme(theme);

  const [orderBy, setOrderBy] = useState(defaultOrderBy);
  const [multipleOrderBy, setMultipleOrderBy] = useState(
    customMultipleOrder.orderBy
  );
  const [orderType, setOrderType] = useState<'asc' | 'desc'>(defaultOrderType);
  const [multipleOrderType, setMultipleOrderType] = useState(
    customMultipleOrder.orderType
  );

  useEffect(() => {
    moment.locale(languageCode);
  }, [languageCode]);

  useEffect(() => {
    setOrderBy(defaultOrderBy);
  }, [defaultOrderBy]);

  useEffect(() => {
    if (!isEmpty(customMultipleOrder)) {
      setMultipleOrderBy(customMultipleOrder.orderBy);
      setMultipleOrderType(customMultipleOrder.orderType);
    }
  }, [customMultipleOrder]);

  const setOrderColumn = (headerPropertyKey) => {
    if (orderBy === headerPropertyKey) {
      const newOrderType =
        orderType === ORDER_TYPE.ASCENDING
          ? ORDER_TYPE.DESCENDING
          : ORDER_TYPE.ASCENDING;

      setOrderType(newOrderType);

      if (!isEmpty(customMultipleOrder)) {
        setMultipleOrderType([newOrderType, ...customMultipleOrder.orderType]);
      }

      return;
    }

    setOrderBy(headerPropertyKey);
    setOrderType(ORDER_TYPE.ASCENDING);

    if (!isEmpty(customMultipleOrder)) {
      setMultipleOrderBy([headerPropertyKey, ...customMultipleOrder.orderBy]);
      setMultipleOrderType([
        ORDER_TYPE.ASCENDING,
        ...customMultipleOrder.orderType,
      ]);
    }
  };

  const interactData = useInteractDataRowAndGraph({
    data,
    headers,
    orderBy,
    orderType,
    maxPerPage,
    currentPage,
    hasPagination,
    customSortProperty,
    customSortFunc,
    multipleOrderBy,
    multipleOrderType,
    customMultipleOrder,
  });

  const handleOpenRow = (item, rowIndex: number, isRowFixed: boolean): void => {
    if (
      !isExpandable ||
      isRowFixed ||
      (!item.nestedContent && !item.graphContent && !item.nestedData)
    ) {
      return;
    }

    interactData.openRow(rowIndex, !!hasNestedData);
  };

  const renderRow = (item, index, isFixed = false) => {
    return (
      <Fragment key={`row-${index}`}>
        <Row
          isHighlighted={isFixed}
          theme={updatedTheme}
          headers={headers}
          item={item}
          isExpandable={isExpandable && !isFixed}
          openRow={() => handleOpenRow(item, index, isFixed)}
          openModal={() => interactData.openModal(index, 'modalOpened')}
          customModalIcon={customModalIcon}
          modalTitle={modalTitle}
          modalHeaders={modalHeaders || []}
          labelModalEmptyState={labelModalEmptyState || ''}
          graphEmptyStateLabel={graphEmptyStateLabel}
          customNestedContentPadding={customNestedContentPadding}
          isBold={isFixed}
          hasNestedData={hasNestedData}
        />
      </Fragment>
    );
  };

  if (isLoading) {
    return (
      <ThemeProvider theme={getTheme(theme, 'nestedList')}>
        <NestedListContainer minWidth={minWidth}>
          <HeaderRow
            theme={theme}
            headers={headers}
            orderBy={orderBy}
            orderType={orderType}
            setOrderColumn={setOrderColumn}
            hasNestedData={hasNestedData}
          />
          <RowsContainer>
            <LoadingState headers={headers} hasNestedData={hasNestedData} />
          </RowsContainer>
        </NestedListContainer>
      </ThemeProvider>
    );
  }

  if (!data.length) {
    return (
      <ThemeProvider theme={getTheme(theme)}>
        <EmptyState
          customIcon={iconEmptyState}
          label={labelEmptyState || ''}
          customSize={iconSizeEmptyState}
        />
        ;
      </ThemeProvider>
    );
  }

  return (
    <ThemeProvider theme={getTheme(theme, 'nestedList')}>
      <NestedListContainer minWidth={minWidth}>
        <GlobalContainer
          fullHeight={hasPagination || isLoading || isExpandable}
        >
          <HeaderRow
            theme={theme}
            headers={headers}
            orderBy={orderBy}
            orderType={orderType}
            setOrderColumn={setOrderColumn}
            hasNestedData={hasNestedData}
          />
          <Container customContentHeight={customContentHeight}>
            {/*
            Handle display of fix rows on top of the listing from fixedRowsData props
            (usually TOTAL lines or something else)
          */}
            {fixedRowsData.length > 0 && (
              <FixedRowsContainer numberFixedItems={fixedRowsData.length}>
                {fixedRowsData.map((item, index) => (
                  <FixedRowContainer
                    key={`fixed-row-container-${index}`}
                    theme={updatedTheme}
                  >
                    {renderRow(item, index, true)}
                  </FixedRowContainer>
                ))}
              </FixedRowsContainer>
            )}
            {/* Handle display of each element in the listing from data props */}
            <RowsContainer
              numberFixedItems={fixedRowsData.length}
              fullHeight={hasPagination || isLoading || isExpandable}
            >
              <BorderedContainer
                theme={updatedTheme}
                noBorderTopRadius={!!fixedRowsData.length}
              >
                {interactData.dataState.map((item, index) => (
                  <RowContainer
                    key={`row-container-${index}`}
                    theme={updatedTheme}
                    noBorderTopRadius={!!fixedRowsData.length}
                  >
                    {renderRow(item, index)}
                  </RowContainer>
                ))}
              </BorderedContainer>
            </RowsContainer>
            {hasPagination && data.length > 0 && (
              <PaginatorContainer>
                <Paginator
                  maxPerPage={maxPerPage}
                  setMaxPerPage={setMaxPerPage}
                  setCurrentPage={setCurrentPage}
                  currentPage={currentPage}
                  itemsCount={data.length}
                  maxPerPageOptions={maxPerPageOptions}
                  hideAllPerPageOption={hideAllPerPageOption}
                />
              </PaginatorContainer>
            )}
          </Container>
        </GlobalContainer>
      </NestedListContainer>
    </ThemeProvider>
  );
};

NestedList.propTypes = {
  minWidth: PropTypes.string,
  headers: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      propertyKey: PropTypes.string.isRequired,
      isNumber: PropTypes.bool,
      unit: PropTypes.string,
      tooltipDisplay: PropTypes.string,
      isSortable: PropTypes.bool.isRequired,
      large: PropTypes.bool,
      narrow: PropTypes.bool,
      customModalRender: PropTypes.bool,
    })
  ).isRequired,
  data: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.any)).isRequired,
  fixedRowsData: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.any)),
  isLoading: PropTypes.bool,
  isExpandable: PropTypes.bool,
  defaultOrderBy: PropTypes.string,
  defaultOrderType: PropTypes.string,
  customMultipleOrder: PropTypes.shape({
    orderBy: PropTypes.arrayOf(string),
    orderType: PropTypes.arrayOf(string),
    customOrderByFunc: PropTypes.func,
  }),
  customModalIcon: PropTypes.string,
  labelEmptyState: PropTypes.string,
  // eslint-disable-next-line react/forbid-prop-types
  iconEmptyState: PropTypes.any,
  iconSizeEmptyState: PropTypes.string,
  labelModalEmptyState: PropTypes.string,
  modalTitle: PropTypes.string,
  modalHeaders: PropTypes.arrayOf(
    PropTypes.shape({
      propertyKey: PropTypes.string.isRequired,
    })
  ),
  // eslint-disable-next-line react/forbid-prop-types
  theme: PropTypes.objectOf(PropTypes.any),
  graphEmptyStateLabel: PropTypes.string,
  languageCode: PropTypes.string,
  hasNestedData: PropTypes.bool,
  hasPagination: PropTypes.bool,
  maxPerPageOptions: PropTypes.arrayOf(PropTypes.number),
  hideAllPerPageOption: PropTypes.bool,
  customSortProperty: PropTypes.string,
  customSortFunc: PropTypes.func,
  customNestedContentPadding: PropTypes.string,
  customContentHeight: PropTypes.string,
};

NestedList.defaultProps = {
  minWidth: '1200px',
  isLoading: false,
  isExpandable: true,
  defaultOrderBy: undefined,
  defaultOrderType: ORDER_TYPE.ASCENDING,
  customMultipleOrder: {},
  customModalIcon: null,
  theme: null,
  labelEmptyState: 'Aucun résultat ne correspond à votre recherche',
  iconEmptyState: null,
  iconSizeEmptyState: null,
  labelModalEmptyState:
    'Aucune commande dans les 15 prochains jours pour cet ingrédient',
  modalTitle: null,
  modalHeaders: [],
  fixedRowsData: [],
  graphEmptyStateLabel: '',
  languageCode: 'fr',
  hasNestedData: false,
  hasPagination: false,
  maxPerPageOptions: [10, 20, 50, 100],
  hideAllPerPageOption: false,
  customSortProperty: null,
  customSortFunc: null,
  customNestedContentPadding: '',
  customContentHeight: '',
};

export default NestedList;
