import React, { useState } from 'react';
import PropTypes from 'prop-types';
import i18next from 'i18next';
import { takeRight } from 'lodash';
import { ThemeProvider } from 'styled-components';

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

import {
  OptionsContainer,
  ActionsContainer,
  ActionsInLineContainer,
  OtherActionsContainer,
} from '../../styledComponents';

import { Props } from './interfaces';
import { SeparateAction } from '../../interfaces';

import Dropdown from '../Dropdown';

import Button from '../../../Button/index';
import SearchBar from '../../../SearchBar';

import Download from '../../../images/icon-download.svg';

function renderDropdownActions(
  actions: SeparateAction[],
  label: string
): JSX.Element {
  if (!actions || !actions.length) {
    return <></>;
  }
  return <Dropdown label={label} actions={actions} />;
}

function renderInlineActions(
  actions: SeparateAction[],
  renderButton: Function,
  maxActionsInLine: number
): JSX.Element {
  if (!actions || !actions.length) {
    return <></>;
  }

  if (actions.length > maxActionsInLine) {
    return (
      <ActionsInLineContainer>
        {actions
          .slice(0, maxActionsInLine)
          .map(({ actionLabel, handleAction, render }) => (
            <div key={`actions-button-${actionLabel}`}>
              {renderButton(render, actionLabel, handleAction)}
            </div>
          ))}
        {actions.length > maxActionsInLine &&
          renderDropdownActions(
            takeRight(actions, actions.length - maxActionsInLine),
            `${i18next.t('COMPONENT_LIST_VIEW_DROPDOWN_OTHER_ACTIONS')} (${
              actions.length - maxActionsInLine
            })`
          )}
      </ActionsInLineContainer>
    );
  }
  return (
    <ActionsInLineContainer>
      {actions.map(({ actionLabel, handleAction, render }) => (
        <div key={`actions-button-${actionLabel}`}>
          {renderButton(render, actionLabel, handleAction)}
        </div>
      ))}
    </ActionsInLineContainer>
  );
}

function renderOtherActions(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  theme: any,
  actions: SeparateAction[],
  renderButton: Function,
  minActionsInActionsDropdown: number
): JSX.Element {
  if (!actions || !actions.length) {
    return <></>;
  }

  const { actionLabel, handleAction, render } = actions[0];

  return (
    <>
      <OtherActionsContainer>
        {actions.length >= minActionsInActionsDropdown ? (
          <Dropdown
            theme={theme}
            actions={actions}
            label={i18next.t('COMPONENT_LIST_VIEW_DROPDOWN_ACTIONS')}
          />
        ) : (
          renderButton(render, actionLabel, handleAction)
        )}
      </OtherActionsContainer>
    </>
  );
}

function renderFixedActions(
  actions: SeparateAction[],
  renderButton: Function
): JSX.Element {
  if (!actions || !actions.length) {
    return <></>;
  }

  return (
    <ActionsInLineContainer>
      {actions.map(({ actionLabel, handleAction, render }) => (
        <div key={`actions-fixed-button-${actionLabel}`}>
          {renderButton(render, actionLabel, handleAction)}
        </div>
      ))}
    </ActionsInLineContainer>
  );
}

function renderActions(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  theme: any,
  actions: SeparateAction[],
  shouldDisplayAction: Function,
  maxActionsInLine: number,
  minActionsInActionsDropdown: number,
  exportFunction?: Function
): JSX.Element {
  const renderButton = (render, actionLabel, handleAction) => {
    if (render) {
      return render(actionLabel, handleAction) as string;
    }
    return (
      <Button
        key={`button-${actionLabel}`}
        formatText={false}
        label={actionLabel}
        handleClick={handleAction}
        fontSize={14}
      />
    );
  };

  const renderExportButton = (label, action) => {
    return (
      <Button
        color="blue-outline-no-shadow"
        formatText={false}
        label={label}
        handleClick={action}
        icon={Download}
        fontSize={14}
      />
    );
  };

  if ((!actions || !actions.length) && !exportFunction) {
    return <></>;
  }

  const displayActions = actions.filter((action) =>
    shouldDisplayAction(action)
  );

  const actionsInLine = displayActions.filter(
    (action) => action.displayActionInLine
  );

  const fixedActions = displayActions.filter((action) => action.fixed);

  const otherActions = displayActions.filter(
    (action) => !action.displayActionInLine && !action.fixed
  );

  if (exportFunction) {
    otherActions.unshift({
      handleAction: exportFunction,
      actionLabel: i18next.t('COMPONENT_LIST_VIEW_EXPORT'),
      displayActionInLine: false,
      render: renderExportButton,
    });
  }

  return (
    <>
      {displayActions && (
        <ActionsContainer>
          {renderInlineActions(actionsInLine, renderButton, maxActionsInLine)}
          {renderOtherActions(
            theme,
            otherActions,
            renderButton,
            minActionsInActionsDropdown
          )}
          {renderFixedActions(fixedActions, renderButton)}
        </ActionsContainer>
      )}
    </>
  );
}

const ListOptions = (props: Props): JSX.Element => {
  const {
    theme,
    actions,
    selectedRows,
    maxActionsInLine,
    hideSearchbar,
    searchInput,
    setSearchInput,
    itemsCount,
    exportFunction,
    placeholderShape,
    placeholderShapePlural,
    renderFilterButton,
    minActionsInActionsDropdown,
  } = props;

  const getPlaceholder = () => {
    if (itemsCount > 1 && placeholderShapePlural) {
      return `${itemsCount} ${placeholderShapePlural}`;
    }
    if (placeholderShape) {
      return placeholderShape;
    }
    return undefined;
  };

  const [placeholder] = useState(getPlaceholder());

  const actionsWithValue = actions.map((action) => ({
    ...action,
    handleAction: () => action.handleAction(selectedRows),
  }));

  const shouldDisplayAction = (action) => {
    if (!action.atLeastOneSelected && !action.multipleSelected) {
      return true;
    }
    if (action.multipleSelected && selectedRows.length > 1) {
      return true;
    }
    if (action.atLeastOneSelected && selectedRows.length) {
      return true;
    }
    return false;
  };

  return (
    <ThemeProvider theme={getTheme(theme, 'listView')}>
      <OptionsContainer>
        {!hideSearchbar && (
          <div style={{ marginRight: '24px' }}>
            <SearchBar
              theme={theme}
              value={searchInput}
              setValue={setSearchInput}
              placeholder={placeholder}
            />
          </div>
        )}
        {renderFilterButton && renderFilterButton()}
        {renderActions(
          theme,
          actionsWithValue,
          shouldDisplayAction,
          maxActionsInLine,
          minActionsInActionsDropdown,
          exportFunction
        )}
      </OptionsContainer>
    </ThemeProvider>
  );
};

ListOptions.propTypes = {
  actions: PropTypes.arrayOf(
    PropTypes.shape({
      fixed: PropTypes.bool,
      actionLabel: PropTypes.string.isRequired,
      displayActionInLine: PropTypes.bool,
      atLeastOneSelected: PropTypes.bool,
      multipleSelected: PropTypes.bool,
      handleAction: PropTypes.func.isRequired,
      render: PropTypes.func,
    })
  ).isRequired,
  // eslint-disable-next-line react/forbid-prop-types
  selectedRows: PropTypes.arrayOf(PropTypes.object).isRequired,
  hideSearchbar: PropTypes.bool,
  searchInput: PropTypes.string.isRequired,
  setSearchInput: PropTypes.func.isRequired,
  maxActionsInLine: PropTypes.number.isRequired,
  itemsCount: PropTypes.number.isRequired,
  exportFunction: PropTypes.func,
  placeholderShape: PropTypes.string,
  placeholderShapePlural: PropTypes.string,
  renderFilterButton: PropTypes.func,
  // eslint-disable-next-line react/forbid-prop-types
  theme: PropTypes.objectOf(PropTypes.any),
  minActionsInActionsDropdown: PropTypes.number.isRequired,
};

ListOptions.defaultProps = {
  exportFunction: null,
  placeholderShape: null,
  renderFilterButton: null,
  placeholderShapePlural: null,
  theme: null,
  hideSearchbar: false,
};

export default ListOptions;
