import React, { Component } from 'react';
import classNames from 'classnames/bind';
import { Switch } from 'react-router';
import { Route, NavLink } from 'react-router-dom';
import Manage from 'components/routes/Generic/Manage';
import Detail from 'components/routes/Generic/Detail';
import Listing from 'components/routes/Generic/Listing';

import {
  handleVarInString,
  getLinkWithVariables,
  getPageInfo,
  getPageTitle,
} from 'store/utils/adminHelpers';
import { transformFunctions, options, models } from 'config/root';

import { config, viewConfig } from 'config/general';
import CustomIcon from 'components/items/CustomIcon';
import OtherItemLayout from 'components/layouts/OtherItemLayout';

import GenericHeader from 'components/pageItems/GenericHeader';
import NavResourceItem from 'components/pageItems/NavResourceItem';
import styleIdentifiers from './resourceItem.scss';

const styles = classNames.bind(styleIdentifiers);

export interface StateProps {
  lg: Record<string, any>;
  content: Record<string, any>;
  detail: Record<string, any>;
  loading: Record<string, any>;
}

export interface DispatchProps {
  load: Function;
  update: Function;
  add: Function;
  reset: Function;
  deleteItem: Function;
  dialogShow: Function;
}

export interface OwnProps {}

export type ResourceItemProps = StateProps & DispatchProps & OwnProps;

interface ResourceItemState {
  ready: boolean;
}

export default class ResourceItem extends Component<ResourceItemProps, ResourceItemState> {
  state = {
    ready: false,
  };

  componentDidMount(): void {
    this.handleLoadData();
    this.handleReset();
  }

  componentDidUpdate(prevProps: ResourceItemProps): void {
    const {
      match: { params },
    } = this.props;

    const prevParams = prevProps && prevProps.match && prevProps.match.params;
    if (prevParams && prevParams.id !== params.id) {
      this.handleLoadData();
    }
  }

  handleReset = () => {
    const { reset } = this.props;

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

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

    const { type } = pageInfo;

    // reset
    reset({
      type,
    });
  };

  handleLoadData = (): void => {
    const { load, loadApollo, detail, reset } = this.props;

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

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

    const { search, type, resourceOptions, id, parentType, parentId } = pageInfo;

    const apiCallOptions =
      (resourceOptions.callApiOptions && resourceOptions.callApiOptions.detail) || {};

    if (!type) return;

    const resourceId = id;
    const resourceType = type;

    if (!id || id === 'external') {
      this.setState({ ready: true });
      return;
    }

    if (detail && detail.data && search.noReset) {
      // do nothing
    } else if (resourceOptions.apollo) {
      loadApollo({
        id: resourceId,
        options: resourceOptions,
      });
    } else {
      load({
        resourceId,
        resourceType,
        parentType,
        parentId,
        reset: true,
        ...apiCallOptions,
      });
    }

    this.setState({
      ready: true,
    });
  };

  submit = (values: Record<string, any>): void => {
    const { update, updateApollo, load, location, history } = this.props;

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

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

    const { id, type, parentType, parentId, modelOptions } = pageInfo;

    const data = (modelOptions.treatData && modelOptions.treatData(values)) || values;

    const resourceId = id;
    const resourceType = type;

    if (modelOptions.apollo) {
      updateApollo({
        options: modelOptions,
        id,
        data: values,
        success: modelOptions.successUpdate,
        callback: (): void => {
          // load({
          //   resourceType,
          //   parentType,
          //   parentId,
          //   resourceId,
          // });
          history.push({
            pathname: `/${config.resourcePath}/${resourceType}/${resourceId}/detail`,
            search: location.search,
          });
        },
      });
      return;
    }

    update({
      resourceId,
      resourceType,
      parentType,
      parentId,
      success: modelOptions.successUpdate,
      data,
      callback: (): void => {
        load({
          resourceType,
          parentType,
          parentId,
          resourceId,
        });
        history.push({
          pathname: `/${config.resourcePath}/${resourceType}/${resourceId}/detail`,
          search: location.search,
        });
      },
    });
  };

  actionItem = item => {
    const {
      match: { params },
      genericAction,
    } = this.props;

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

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

    const { type, parentType, parentId } = pageInfo;

    genericAction({
      resourceType: type,
      parentType,
      parentId,
      resourceId: params.id,
      id: params.id,
      // other params
      api: item.api,
      success: item.success,
      url: item.url,
      method: item.method,
      callback: item.callback,
    });
  };

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

    if (!params.type || !params.id) return;

    history.push({
      pathname: `/${config.resourcePath}/${params.type}/${params.id}/update`,
      search: location.search,
    });
  };

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

    if (!params.type || !params.id) return;

    history.push({
      pathname: `/${config.resourcePath}/${params.type}/${params.id}/detail`,
      search: location.search,
    });
  };

  back = (): void => {
    const { history } = this.props;

    history.goBack();
  };

  handleCallbackDelete = () => {
    const { history } = this.props;

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

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

    const { type, parentType, parentId, modelOptions } = pageInfo;

    const resourceType = type;

    if (modelOptions.deleteBack) {
      history.goBack();
    } else if (parentType && parentId) {
      history.push({
        pathname: `/${config.resourcePath}/${parentType}/${parentId}/listData/${resourceType}`,
        // Avoiding error in config with separated resource
        // search: location.search,
      });
    } else {
      history.push({
        pathname: `/${config.resourcePath}/${resourceType}`,
        search: location.search,
      });
    }
  };

  handleDelete = () => {
    const { deleteApollo, deleteItem } = this.props;

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

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

    const { id, type, data, parentType, parentId, modelOptions } = pageInfo;

    const resourceId = id;
    const resourceType = type;

    if (modelOptions.apollo) {
      deleteApollo({
        id: data[config.idKey] || resourceId,
        options: modelOptions,
        callback: this.handleCallbackDelete,
        inputs: modelOptions.deleteInputs || {},
      });
      return;
    }
    deleteItem({
      resourceId,
      resourceType,
      parentId,
      parentType,
      callback: this.handleCallbackDelete,
    });
  };

  deleteItem = (): void => {
    const { dialogShow } = this.props;

    dialogShow({
      id: 'confirm',
      title: 'admin.messages.deleteResourceTitle',
      messages: 'admin.messages.deleteResourceText',
      action: {
        color: 'primary',
        value: () => {
          this.handleDelete();
        },
      },
    });
  };

  getTransformedData = (item, res) => {
    if (typeof item === 'string') return {};

    let data = {};

    if (item) {
      const { transformFunction } = item;

      if (transformFunction) {
        data = transformFunction(res);
      }
    }

    return data;
  };

  renderStatusInfo = (item, index) => {
    if (typeof item !== 'object') return <div className={styles(`info${index}`)} />;

    if (item.active) return <div className={styles(`info${index}`, 'label')}>{item.label}</div>;

    return false;
  };

  renderStatus = (data, resOption) => {
    const headerStatus = resOption.headers?.find(e => e.type === 'status');

    if (!data || (data && !data[headerStatus?.key])) return false;

    const dynamicInfos = this.getTransformedData(resOption, data);

    if (dynamicInfos && dynamicInfos.infos) {
      return (
        <div className={styles('status')}>
          <div className={styles('infos', 'label-info')}>
            {dynamicInfos.infos.info1 ? this.renderStatusInfo(dynamicInfos.infos.info1, 1) : false}
            {dynamicInfos.infos.info2 ? this.renderStatusInfo(dynamicInfos.infos.info2, 2) : false}
            {dynamicInfos.infos.info3 ? this.renderStatusInfo(dynamicInfos.infos.info3, 3) : false}
            {dynamicInfos.infos.info4 ? this.renderStatusInfo(dynamicInfos.infos.info4, 4) : false}
            {dynamicInfos.infos.info5 ? this.renderStatusInfo(dynamicInfos.infos.info5, 5) : false}
          </div>
        </div>
      );
    }

    return false;
  };

  renderTitle = (resourceOptions, data) => {
    const {
      content,
      lg,
      location: { pathname },
    } = this.props;

    let type = 'detail';
    if (pathname.includes('/update')) type = 'update';

    const title = getPageTitle(resourceOptions, data, {
      content,
      lg,
      type,
    });

    return title;
  };

  render(): JSX {
    const {
      content,
      lg,
      form,
      loading,
      detail,
      location: { pathname },
    } = this.props;

    const { ready } = this.state;

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

    if (typeof pageInfo === 'string') return <span>{pageInfo}</span>;

    const { type, index, resourceOptions, dataOptions, listDataOptions } = pageInfo;

    const data = detail && detail.data;

    // here we display
    const nav = (index && listDataOptions && listDataOptions.nav) || resourceOptions.nav;

    const edit = data && data[config.idKey];

    const title = this.renderTitle(resourceOptions, data);

    const editPage = pathname.includes('/update');
    const detailPage = pathname.includes('/detail');

    // Other actions
    const resourceOtherActions = resourceOptions.actions;

    if (!ready) return <span />;

    return (
      <div className={styles('ResourceItem')}>
        <GenericHeader
          className={styles('header')}
          status={this.renderStatus(data, resourceOptions)}
          loading={loading}
          // noBack={dataOptions}
          detailAction={!dataOptions && !detailPage ? this.detail : undefined}
          editAction={!dataOptions && !resourceOptions.noUpdate && !editPage && this.edit}
          saveAction={
            !dataOptions && editPage ? () => this.submit(form?.getState()?.values) : undefined
          }
          deleteAction={!dataOptions && !resourceOptions.noDelete ? this.deleteItem : undefined}
          title={this.renderTitle(resourceOptions, data)}
          id={resourceOptions.displayId && data && data[config.idKey]}
          pageInfo={pageInfo}
          label={resourceOptions.actionsLabel}
          actions={!dataOptions && resourceOtherActions}
        />
        <NavResourceItem className={styles('nav')} nav={nav} options={options} {...this.props} />
        <div className={styles('container')}>
          <div className={styles('content', nav && 'with-nav')}>
            <Switch>
              <Route path={`/${config.resourcePath}/:type/:id/update`} component={Manage} />
              <Route exact path={`/${config.resourcePath}/:type/:id/detail`} component={Detail} />
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/actions/:form`}
                component={Manage}
              />
              {/* Sub data of the object in a separated view */}
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/subdata/:subData/detail`}
                component={Detail}
              />
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/subdata/:subData/update`}
                component={Manage}
              />
              {/* One item of an object list data in a separated view to add or update one */}
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/listdata/:listData/create`}
                component={Manage}
              />
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/listdata/:listData/:index/update`}
                component={Manage}
              />
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/listdata/:listData/:index/detail`}
                component={Detail}
              />
              <Route
                exact
                path={`/${config.resourcePath}/:type/:id/listdata/:listData`}
                component={Listing}
              />
              <Route
                exact
                path={`/${config.resourcePath}/:parentType/:parentId/e`}
                component={OtherItemLayout}
              />
              {/* Sub listing (using apis) */}
              <Route
                exact
                path={`/${config.resourcePath}/:parentType/:parentId/:type`}
                component={Listing}
              />
              <Route component={OtherItemLayout} />
            </Switch>
          </div>
        </div>
      </div>
    );
  }
}
