import * as React from 'react';
import classNames from 'classnames/bind';
import TextItem from 'components/items/TextItem';
import { models, options, transformFunctions } from 'config/root';
import CustomFixedTable from 'components/enhancers/CustomFixedTable';
// import GenericFiltersForm from 'components/forms/GenericFiltersForm';
import TableListItem from 'components/listItems/TableListItem';
import ModuleButton from 'components/items/ModuleButton';

import { config } from 'config/general';
import { getPageInfo, getLinkWithVariables } from 'store/utils/adminHelpers';
import { filter, clone } from 'lodash';
import ModuleList from 'components/pageItems/ModuleList';
import styleIdentifiers from './listing.scss';

const styles = classNames.bind(styleIdentifiers);

const EnhancedTable = CustomFixedTable(TableListItem);

export interface ListingProps {
  match: Record<string, any>;
  load: Function;
  linkedLoad: Function;
  linkedLoadMore: Function;
  list: Record<string, any>;
  linkedList: Record<string, any>;
  history?: Record<string, any>;
  loadMore: Function;
  exportList: Function;
  lg?: string;
}

interface ListingState {}

export default class Listing extends React.Component<ListingProps, ListingState> {
  componentDidMount() {
    const {
      history,
      match: { params },
      resetHistory,
    } = this.props;
    // Allow the redirection to the default url from OtherLayout (should not be required)
    if (!params.type && history) {
      history.push(config.defaultUrl);
    }

    // only reset for list pages
    if (!params.listData && !params.subData && !params.parentType) resetHistory();

    this.handleLocation();
  }

  componentDidUpdate(prevProps) {
    const { location, match, resetHistory } = this.props;

    if (location !== prevProps.location) {
      // Reset if new type
      if (prevProps.match !== match) {
        const params = match.params;
        // only reset for list pages
        if (!params.listData && !params.subData && !params.parentType) resetHistory();
      }

      this.handleLocation();
    }
  }

  handleLocation = () => {
    const {
      match: { params },
      pushHistory,
    } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    if (typeof pageInfo === 'string') return;

    const { modelOptions, allParams } = pageInfo;

    const { type, parentType, subData, listData, form } = allParams;

    let historyId = type;
    if (subData || listData || form || parentType) {
      historyId += `_detail_sublevel`;
    } else {
      historyId += '_list';
    }

    pushHistory({
      pathname: location.pathname,
      search: location.search,
      params,
      id: historyId,
      name: modelOptions.titleList || modelOptions.title,
    });
  };

  loadData = (filters: Record<string, any>) => {
    const {
      load,
      loadMore,
      loadMoreApollo,
      loadApollo,
      match: { params },
    } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    const { listData, modelOptions } = pageInfo;

    if (listData) {
      return;
    }

    const data = {
      parentType: params.parentType,
      parentId: params.parentId,
      resourceType: params.type,
    };

    const filterHash = JSON.stringify(filters || {});

    if (modelOptions.apollo) {
      let treatedInputs = clone(modelOptions.inputs);

      if (filters) {
        treatedInputs = { ...treatedInputs, ...filters };
      }

      if (treatedInputs) {
        for (let index = 0; index < Object.entries(treatedInputs).length; index++) {
          const element = Object.entries(treatedInputs)[index];

          const inputKey = element[0];
          const inputValue = element[1];

          const variable = typeof inputValue === 'string' && inputValue.replace(/\$/g, '');
          if (data[variable]) {
            treatedInputs[inputKey] = data[variable];
          }
        }
      }

      if (filters.more) {
        // more cannot be sent to apollo
        delete treatedInputs.more;

        loadMoreApollo({
          options: modelOptions,
          ...filters,
          inputs: treatedInputs,
          filterHash,
        });
      } else if (load) {
        loadApollo({
          options: modelOptions,
          ...filters,
          inputs: treatedInputs,
          filterHash,
        });
      }

      return;
    }

    if (filters.more) {
      loadMore({
        ...data,
        ...filters,
        filterHash,
      });
    } else if (load) {
      load({
        ...data,
        ...filters,
        filterHash,
      });
    }
  };

  addItem = () => {
    const { match, resetDetail, history } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    resetDetail();

    const type = match.params.type;

    if (pageInfo?.modelOptions?.createLinkCustom) {
      history.push(pageInfo.modelOptions.createLinkCustom);
      return;
    }

    if (history) history.push(`/${config.resourcePath}/${type}/create`);
  };

  addListItem = () => {
    const {
      location,
      match: { params },
      history,
    } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    if (typeof pageInfo === 'string') return;

    const { type, modelOptions } = pageInfo;

    const { id, listData } = params;

    if (listData && modelOptions.separatedPost) {
      history.push({
        pathname: `/${config.resourcePath}/${modelOptions.resource || listData}/create`,
        search: `?parentType=${type}&parentId=${id}`,
      });
      return;
    }

    if (history)
      history.push({
        pathname: `/${config.resourcePath}/${type}/${id}/listdata/${listData}/create`,
        search: location.search,
      });
  };

  exportData = () => {
    const { exportList } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    if (typeof pageInfo === 'string') return;

    const { type, modelOptions } = pageInfo;

    exportList({
      resourceType: type,
      api: modelOptions.exportApi,
    });
  };

  otherExport = () => {
    const { exportList } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    if (typeof pageInfo === 'string') return;

    const { type, modelOptions } = pageInfo;

    exportList({
      resourceType: type,
      api: modelOptions.otherExport.api,
    });
  };

  renderActions = () => {
    const {
      match: { params },
      history,
    } = this.props;

    const pageInfo = getPageInfo(this.props, options);

    if (typeof pageInfo === 'string') return false;

    const { modelOptions, listDataOptions, resourceOptions } = pageInfo;

    // For now

    if (params.parentType && resourceOptions.addLink) {
      return (
        <div className={styles('buttons')}>
          <ModuleButton
            noMargin
            label={resourceOptions.addLabel || 'New'}
            iconLeft="plus"
            action={() => {
              history.push(getLinkWithVariables(resourceOptions.addLink, pageInfo));
            }}
            relative
          />
        </div>
      );
    }

    if (params.parentType) return false;

    if (params.listData) {
      return (
        <div className={styles('buttons')}>
          {listDataOptions && !listDataOptions.noCreate && (
            <ModuleButton
              noMargin
              label={listDataOptions.addLabel || 'New'}
              iconLeft="plus"
              action={this.addListItem}
              relative
            />
          )}
        </div>
      );
    }
    return (
      <>
        <div className={styles('buttons')}>
          {modelOptions.exportApi && (
            <ModuleButton
              className={styles('export-button')}
              color="secondary"
              noMargin
              icon="file-export"
              action={this.exportData}
              relative
            />
          )}
          {modelOptions.otherExport && (
            <ModuleButton
              color="green"
              noMargin
              label={modelOptions.otherExport.label}
              iconLeft="file-export"
              action={this.otherExport}
              relative
            />
          )}
          {!modelOptions.noCreate && (
            <ModuleButton
              noMargin
              label={modelOptions.addLabel || 'New'}
              iconLeft="plus"
              action={this.addItem}
              relative
            />
          )}
        </div>
      </>
    );
  };

  getListItems = () => {
    const { list, detail } = this.props;

    let listingData = list || {};

    const pageInfo = getPageInfo(this.props, options, null, transformFunctions);

    const { listData } = pageInfo;

    if (listData) {
      listingData = {
        ...detail,
        data: detail && detail.data && detail.data[listData],
      };
    }

    if (options[pageInfo?.type]?.filterList && listingData?.data) {
      return options[pageInfo?.type].filterList(listingData.data);
    }

    return listingData.data;
  };

  render() {
    const {
      match: { params },
      list,
      detail,
      lg,
    } = this.props;

    const pageInfo = getPageInfo(this.props, options, models, transformFunctions);

    if (typeof pageInfo === 'string') return false;

    const { type, listData, modelOptions, transformFunction } = pageInfo;

    const listOptions = modelOptions;

    if (!listOptions) return false;

    const customProps = {
      type,
      noUpdate: listOptions.noUpdate,
      noDetail: listOptions.noDetail,
      noDelete: listOptions.noDelete,
      doubleTap: listOptions.doubleTap,
      newTab: listOptions.newTab,
      rowHeight: listOptions.rowHeight,
      detailLink: listOptions.detailLink,
      editLink: listOptions.editLink,
      fastDelete: listOptions.fastDelete,
      fastActions: listOptions.fastActions,
      listData,
    };

    let listingData = list || {};

    if (listData) {
      listingData = {
        ...detail,
        data: detail && detail.data && detail.data[listData],
      };
    }

    const items = this.getListItems();

    const subNav = listOptions?.subNav;

    return (
      <ModuleList
        className={styles('Listing')}
        noBorderTitle
        options={listOptions}
        subNav={subNav}
        rightActions={this.renderActions()}
      >
        <EnhancedTable
          virtual
          lg={lg}
          noModule={!listOptions.module}
          headers={listOptions.headers || []}
          legend={listOptions?.legend}
          actions={this.renderActions()}
          loading={listingData.loading}
          loaded={listingData.loaded}
          items={items}
          transformFunction={transformFunction}
          itemProps={customProps}
          // filtersProps={customProps}
          // displayFilters={!listData && listOptions.filters}
          loadFunc={this.loadData}
          listOptions={listOptions}
          noMore={listData || listOptions.hideMore || listingData.noMore}
          noCheckbox
          noHeader
        />
      </ModuleList>
    );
  }
}
