import * as React from 'react';
import classNames from 'classnames/bind';
import CustomIcon from 'components/items/CustomIcon';
import PageForm from 'components/forms/PageForm';
import ModuleButton from 'components/items/ModuleButton';
import { Form } from 'react-final-form';
import PageCmsForm from 'components/forms/PageCmsForm';
import { Route, Redirect, NavLink } from 'react-router-dom';
import { orderBy, filter, find } from 'lodash';
import { config } from 'config/general';
import PageFilterForm from 'components/forms/PageFilterForm/PageFilterForm';
import TextItem from 'components/items/TextItem';
import isEqual from 'lodash/isEqual';
import styleIdentifiers from './content.scss';

const styles = classNames.bind(styleIdentifiers);

interface PagesStateProps {
  loading: boolean;
  data: Record<string, any>[];
  loaded: boolean;
}

export interface ContentProps {
  pages: null | PagesStateProps;
  loadList: Function;
  history: Record<string, any>;
  match: Record<string, any>;
  sideMenuShow: Function;
  dialogShow: Function;
  addPage: Function;
  updatePage: Function;
  deletePage: Function;
  sideMenuHide: Function;
}

interface ContentState {
  content: Record<string, any> | null;
}

export default class Content extends React.Component<ContentProps, ContentState> {
  constructor(props) {
    super(props);
    this.state = {
      initialValues: null,
    };
    this.autoRefresh();
  }

  componentDidMount() {
    const { loadList } = this.props;
    loadList({
      reset: true,
    });
  }

  componentDidUpdate() {
    this.handleFirstPage();
    this.handleCurrentPage();
  }

  componentWillUnmount() {
    if (this.intervalID) clearInterval(this.intervalID);
  }

  autoRefresh = () => {
    const { loadList } = this.props;

    if (!config.reloadContentTime) return;

    if (this.intervalID) clearInterval(this.intervalID);

    this.intervalID = setInterval(() => {
      loadList({
        noLoading: true,
      });
    }, config.reloadContentTime * 1000);
  };

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

    if (pages && pages.loaded) {
      const list = this.orderedPages();
      const first = find(list, item => !item.hide);

      if (!params.id && first) history.push(`/${config.contentPath}/${first[config.idKey]}`);
    }
  };

  handleCurrentPage = () => {
    const { initialValues } = this.state;
    const page = this.currentPage();

    if (!page) return;

    const targetValues = {
      [config.cmsBaseName]: page.content,
    };

    // change initial values only if page content has changed
    if (!isEqual(initialValues, targetValues)) {
      this.setState({
        initialValues: targetValues,
      });
    }
  };

  orderedPages = () => {
    const { pages } = this.props;
    const { filterPage } = this.state;

    let pageData = pages && pages.data;

    if (filterPage && filterPage.length) {
      pageData = filter(pageData, it => {
        const keys = Object.keys(it);
        for (let i = 0; i < keys.length; i += 1) {
          const key = keys[i];
          let elem = it[key];

          if (typeof elem === 'string') {
            elem = elem.toLowerCase();
            if (elem.indexOf(filterPage.toLowerCase()) >= 0) return true;
          }
        }
        return false;
      });
    }

    if (pageData) {
      return orderBy(
        pageData,
        (item: Record<string, any>) => {
          if (config.orderByCMS && item[config.orderByCMS]) return item[config.orderByCMS];
          return 0;
        },
        [config.orderByDirectionCMS],
      );
    }
    return [];
  };

  submitPage = (values: Record<string, any>) => {
    const { updatePage, addPage, history, sideMenuHide } = this.props;

    values.state = values.title;

    if (values.position) values.position = parseInt(values.position, 10);

    if (values[config.idKey]) {
      updatePage({
        id: values[config.idKey],
        data: values,
        callback: () => sideMenuHide('right'),
      });
    } else {
      addPage({
        data: {
          ...values,
          content: {},
        },
        callback: res => {
          sideMenuHide('right');
          history.push(`/${config.contentPath}/${res[config.idKey]}`);
        },
      });
    }
  };

  deletePage = (item: Record<string, any>) => {
    const { deletePage, dialogShow, history, sideMenuHide } = this.props;

    dialogShow({
      id: 'confirm',
      title: 'admin.addPage.delete',
      messages: 'admin.addPage.confirmDelete',
      action: {
        color: 'primary',
        value: () => {
          deletePage({
            id: item[config.idKey],
            callback: () => {
              sideMenuHide('right');
              const list = this.orderedPages();
              const first = list && list[0];
              if (first) history.push(`/${config.contentPath}/${first[config.idKey]}`);
            },
          });
        },
      },
    });
  };

  showPageForm = (item: Record<string, any>) => {
    const { sideMenuShow } = this.props;

    sideMenuShow({
      id: 'right',
      content: (
        <Form
          component={PageForm}
          edit={item && item[config.idKey]}
          onSubmit={this.submitPage}
          deleteItem={() => this.deletePage(item)}
          initialValues={item}
        />
      ),
    });
  };

  currentPage = () => {
    const {
      match: { params },
      pages,
    } = this.props;

    const pagesList = pages && pages.data;

    // eslint-disable-next-line
    const currentPage = find(
      pagesList,
      // eslint-disable-next-line
      (item: Record<string, any>) => item[config.idKey] == params.id,
    );

    if (!currentPage) return false;

    return currentPage;
  };

  editContent = (values: Record<string, any>) => {
    const page = this.currentPage();
    if (!page) return;
    const { updatePage } = this.props;

    updatePage({
      id: page[config.idKey],
      data: {
        ...page,
        content: values[config.cmsBaseName],
      },
    });
  };

  renderPage = (item: Record<string, any>, index: number) => {
    const { search } = this.props;
    if (search.filter && item.hide) return false;

    const link = `/${config.contentPath}/${item[config.idKey]}`;
    return (
      <div className={styles('item-wrapper')} key={index}>
        <NavLink
          to={link}
          className={styles('item', 'link-wrapper')}
          activeClassName={styles('state-active')}
          isActive={(match, location) => {
            return location?.pathname?.indexOf(link) >= 0;
          }}
        >
          <span>{item.label}</span>
          {!item.filterMatch && item.toComplete && (
            <span className={styles('to-complete')}>{item.stats.toComplete}</span>
          )}
          {item.filterMatch > 0 && (
            <span className={styles('filter-match')}>{item.filterMatch}</span>
          )}
        </NavLink>
        <div className={styles('edit')} onClick={() => this.showPageForm(item)}>
          <CustomIcon className={styles('icon')} icon="pen" />
        </div>
      </div>
    );
  };

  search = values => {
    const { globalSearch } = this.props;

    if (values.filter && values.filter.length > 0 && values.filter.length < 3) return;

    if (this.timeout) clearTimeout(this.timeout);

    this.timeout = setTimeout(() => {
      globalSearch(values.filter);
    }, 200);
  };

  filterSearch = values => {
    this.setState({
      filterPage: values.filter,
    });
  };

  render() {
    const { pages, syncContent, search } = this.props;
    const { initialValues } = this.state;

    const page = this.currentPage();

    return (
      <div className={styles('Content')}>
        {pages && (
          <>
            <div className={styles('nav-pages')}>
              <div className={styles('nav-header')}>
                <Form
                  onSubmit={this.filterSearch}
                  placeholder="Filter"
                  component={PageFilterForm}
                />
              </div>
              <div className={styles('nav-content')}>
                {this.orderedPages().map(this.renderPage)}
              </div>
              <div className={styles('nav-footer')}>
                <div className={styles('nav-footer-content')} onClick={() => this.showPageForm({})}>
                  <TextItem path="admin.buttons.addPage" />
                </div>
                {config.syncContent && (
                  <div className={styles('bottom', 'green')} onClick={() => syncContent()}>
                    <span>
                      {config.dev || config.staging ? 'Update production' : 'Update staging'}
                    </span>
                  </div>
                )}
              </div>
            </div>
            <div className={styles('page-content')}>
              <div className={styles('global-search')}>
                <div className={styles('form-wrapper')}>
                  <Form onSubmit={this.search} initialValues={search} component={PageFilterForm} />
                </div>
              </div>
              {page && initialValues && (
                <Form
                  pageId={page[config.idKey]}
                  initialValues={initialValues}
                  component={PageCmsForm}
                  search={search}
                  page={page}
                  completion={page.stats}
                  onSubmit={this.editContent}
                />
              )}
            </div>
          </>
        )}
      </div>
    );
  }
}
