import * as React from 'react';
import classNames from 'classnames/bind';
import InputLanguage from 'components/formHelpers/InputLanguage';

// import { Field } from 'redux-form';
import { Field, Form } from 'react-final-form';

import _ from 'lodash';
import ModuleButton from 'components/items/ModuleButton';
import { config, viewConfig } from 'config/general';
import Input from 'components/formItems/Input';
import OnBlurInput from 'components/formItems/OnBlurInput';
import { camelize, clone, copyClipboard } from 'store/utils/helper';
import CustomSelect from 'components/formItems/CustomSelect';
import Checkbox from 'components/formItems/Checkbox';
import Percentage from 'components/items/Percentage';
import { handleCompletion, handleFusion } from 'store/utils/adminHelpers';
import UploadCmsImageForm from 'components/forms/UploadCmsImageForm';
import { FaLock, FaUnlock, FaTrash } from 'react-icons/fa';
import styleIdentifiers from './pageCmsForm.scss';
import {
  sectionTemplate,
  seoTemplate,
  actionsTemplate,
  fieldTemplate,
  modalTemplate,
  listTemplate,
} from './template';

const styles = classNames.bind(styleIdentifiers);

export interface PageCmsFormProps {
  handleSubmit: Function;
  submitting?: boolean;
  valid?: boolean;
  initialValues: {};
  values: {};
  dialogError: Function;
  dialogShow: Function;
  change: Function;
  upload: Function;
}

const FIELD_TYPES = [
  { label: 'Text', value: 'input' },
  { label: 'Textarea', value: 'textarea' },
  { label: 'Wysiwyg', value: 'wysiwyg' },
  { label: 'Value', value: 'value' },
  { label: 'Image', value: 'img' },
  { label: 'Link', value: 'link_abs' },
  { label: 'Boolean', value: 'bool' },
  { label: 'Code', value: 'code' },
];

const STRUCTURAL_TYPES = [
  { label: 'Object', value: 'Object' },
  { label: 'Array', value: 'Array' },
  { label: 'List', value: 'list' },
  { label: 'Field', value: 'field' },
  { label: 'Section', value: 'section' },
  { label: 'Modal', value: 'modal' },
  { label: 'Actions', value: 'actions' },
  { label: 'SEO', value: 'seo' },
];

const ALL_TYPES = FIELD_TYPES.concat(STRUCTURAL_TYPES);

const STRUCTURAL_VALUES = ['Array', 'array', 'Object', 'object'];
const FIELD_VALUES = FIELD_TYPES.reduce((acc, item) => {
  acc.push(item.value);
  return acc;
}, []);

export default class PageCmsForm extends React.Component<PageCmsFormProps, PageCmsFormState> {
  constructor(props: PageCmsFormProps) {
    super(props);
    this.state = {
      latestValues: null,
    };
  }

  componentDidUpdate(prevProps) {
    const { initialValues, values, pageId, search } = this.props;

    if (!config.reloadContentTime) return;

    const { latestValues } = this.state;

    const prevFilter = prevProps && prevProps.search && prevProps.search.filter;
    const newFilter = search && search.filter;

    const prevValues = prevProps.values;

    const prevInitial = prevProps.initialValues;

    // new page / search => reset latest
    if (pageId !== prevProps.pageId || newFilter !== prevFilter) {
      this.saveLatestChange(null);
    }
    // save latest value
    else if (values !== prevValues) {
      this.saveLatestChange(values);
    }

    // initialValues has changed => fusion to keep latest changes
    if (prevInitial !== initialValues) {
      // usage of clone to avoid changing the object in the reducer
      const latest = latestValues && clone(latestValues[config.cmsBaseName]);
      const newVal = initialValues && clone(initialValues[config.cmsBaseName]);
      const fusion = handleFusion(newVal, latest);

      this.refreshContent(fusion);
    }
  }

  saveLatestChange = values => {
    this.setState({
      latestValues: values,
    });
  };

  toggle = (base: string) => {
    const { values } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(base, copy);
    if (node) node.open = !node.open;

    this.refreshContent(copy);
  };

  getInfoNode = (base: string, values: {}) => {
    const node = _.get(values, base);
    const nodeContent = (node && node.content) || node;

    const newItem = node && node[config.keyNewContent];

    return {
      node,
      nodeContent,
      newItem,
    };
  };

  refreshContent = (newContent: {}) => {
    const { form } = this.props;

    const content = clone(newContent[config.cmsBaseName] || newContent);
    handleCompletion(content);

    form.change(config.cmsBaseName, content);

    // force redraw
    // this.forceUpdate();
  };

  addNewItem = (base: string, index?: number) => {
    const { values, dialogError } = this.props;

    const copy = clone(values);
    const parent = this.getInfoNode(base, copy);

    const newItem = parent.newItem;
    if (!newItem) return;

    let label = newItem.key;
    let dataKey = newItem.key;

    let type = newItem.type;
    let content = {};

    // next new item
    let nextNewItem;

    // Seo object
    if (type === 'seo') {
      type = 'Object';
      dataKey = 'seo';
      label = 'Seo content';
      content = seoTemplate;
    } else if (dataKey && dataKey.indexOf(' ') >= 0) {
      dataKey = camelize(dataKey);
    } else if (dataKey) {
      dataKey = config.camelizeContentKeys ? camelize(dataKey) : dataKey;
    }

    if (type === 'section') {
      type = 'Object';
      content = sectionTemplate;
    }
    if (type === 'modal') {
      type = 'Object';
      content = modalTemplate;
    }
    if (type === 'field') {
      type = 'Object';
      content = fieldTemplate;
    }
    if (type === 'actions') {
      type = 'Object';
      content = actionsTemplate;
    }

    if (!type || !dataKey) {
      dialogError({
        data: 'Select a type and enter a key',
      });
      return;
    }

    if (dataKey.indexOf('.') >= 0) {
      dialogError({
        data: 'You cannot use "." in your label',
      });
      return;
    }

    // AVOID RESERVED KEYS
    if (config.reservedKeysCMS.indexOf(dataKey) >= 0) {
      dialogError({
        data: 'The key entered is a reserved word',
      });
      return;
    }

    if (type === 'Array') {
      content = [];
    }
    if (STRUCTURAL_VALUES.indexOf(type) >= 0) {
      nextNewItem = {
        type: 'input',
      };
    }

    // Array of objects
    if (type === 'list') {
      type = 'Array';
      content = listTemplate;
      nextNewItem = {
        type: 'Object',
        key: 'item',
      };
    }

    // key will be added by iteration
    const newObj = {
      label,
      position: index + 1,
      type,
      index,
      content,
      toComplete: STRUCTURAL_VALUES.indexOf(type) < 0,
      locked: false,
      lockedValue: false,
      [config.keyNewContent]: nextNewItem,
    };

    if (parent.nodeContent[dataKey]) {
      dialogError({
        data: 'Key already used',
      });
      return;
    }

    if (parent.node.type === 'Array') {
      const current = parent.nodeContent;
      newObj.label = newObj.label || '';
      for (let i = 0; i < current.length; i++) {
        const it = current[i];
        if (it.label === newObj.label) {
          newObj.label += ` ${index + 1}`;
          break;
        }
      }
      current.push(newObj);
    } else {
      parent.nodeContent[dataKey] = newObj;
    }

    this.refreshContent(copy);
  };

  deleteItem = (base: string, baseItem: string, key: string) => {
    const { values, dialogShow } = this.props;

    const copy = clone(values);

    const parent = this.getInfoNode(base, copy);
    const item = this.getInfoNode(baseItem, copy);

    const deleteRefresh = () => {
      if (parent.node.type === 'Array') {
        parent.nodeContent.splice(key, 1);
      } else {
        parent.nodeContent[key] = undefined;
      }

      this.refreshContent(copy);
    };

    if (item.node.type === 'Object' || item.node.type === 'Array') {
      dialogShow({
        id: 'confirm',
        title: 'Confirmation',
        messages: 'Are you sure you want to delete this element?',
        action: {
          color: 'primary',
          value: deleteRefresh,
        },
      });
    } else {
      deleteRefresh();
    }
  };

  uploadImage = baseItem => {
    const { sideMenuShow } = this.props;
    sideMenuShow({
      id: 'right',
      content: (
        <Form
          component={UploadCmsImageForm}
          onSubmit={val => {
            const res = val.image;
            this.registerImageUploaded(baseItem, res);
          }}
        />
      ),
    });
  };

  removeUploadedImage = baseItem => {
    const { values } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(baseItem, copy);

    if (node) {
      node.content = {};
      node.src = null;
    }

    this.refreshContent(copy);
  };

  registerImageUploaded = (baseItem, image) => {
    const { sideMenuHide, values } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(baseItem, copy);

    if (image && node) {
      node.content = {};
      node.src = image;
    }

    sideMenuHide('right');
    this.refreshContent(copy);
  };

  lockChild = (content, lock) => {
    for (let index = 0; index < Object.values(content).length; index++) {
      const element = Object.values(content)[index];
      if (element.label) {
        element.locked = lock;
        if (element.content) {
          this.lockChild(element.content, lock);
        }
      }
    }
  };

  lockItemValue = (baseItem, item) => {
    const { values, user, dialogError } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(baseItem, copy);

    if (user && user.types && !user.types.includes('admin')) {
      dialogError({
        data: "This account doesn't have the permission to do this task",
      });
      return;
    }

    if (node) {
      node.lockedValue = !item.lockedValue;
    }

    this.refreshContent(copy);
  };

  lockItem = (baseItem, item) => {
    const { values, dialogShow, user, dialogError } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(baseItem, copy);

    if (user && user.types && !user.types.includes('admin')) {
      dialogError({
        data: "This account doesn't have the permission to do this task",
      });
      return;
    }

    const lockElement = () => {
      node.locked = !item.locked;

      if (node.content) {
        this.lockChild(node.content, !item.locked);
      }

      this.refreshContent(copy);
    };

    if (node && node.locked && (node.type === 'Object' || node.type === 'Array')) {
      dialogShow({
        id: 'confirm',
        title: 'Confirmation',
        messages: 'Are you sure you want to unlock this element and its childs ?',
        action: {
          color: 'primary',
          value: lockElement,
        },
      });
    } else if (node) {
      lockElement();
    }
  };

  handlePositionBlur = (base, position) => {
    const { values } = this.props;

    const copy = clone(values);
    const { node } = this.getInfoNode(base, copy);

    node.position = position;
    this.refreshContent(copy);
  };

  copyPath = path => {
    const { dialogSuccess } = this.props;
    copyClipboard(path);
    dialogSuccess({
      data: 'admin.messages.pathCopied',
    });
  };

  renderMeta = (item: {}, type: string, base: string, otherItem) => {
    const { page } = this.props;

    let path = base.replace(config.cmsBaseName, page.title);
    path = path.replace(/\.content\./g, '.');
    path = path.replace(/\.content\[/g, '[');

    return (
      <div className={styles('meta', type)}>
        <div className={styles('left')}>
          <span>
            {`${type} key -`}
            &nbsp;
          </span>
          <span className={styles('key')}>{item.key}</span>
          <span>&nbsp;/ Position -&nbsp;</span>
          <Field
            className={styles('position')}
            name={`${base}.position`}
            component={OnBlurInput}
            inputType="number"
            value={item.position}
            handleBlur={pos => this.handlePositionBlur(base, pos)}
          />
          <span>&nbsp; / Path - &nbsp;</span>
          <div className={styles('path')} onClick={() => this.copyPath(path)}>
            {path}
          </div>
        </div>
        <div className={styles('right')}>
          {otherItem}
          {STRUCTURAL_VALUES.indexOf(type) < 0 && (
            <Field
              noMargin
              className={styles('checkbox')}
              labelClassName={styles('label')}
              component={Checkbox}
              activeClassName={styles('active-checkbox')}
              useBox
              type="checkbox"
              label="Uncomplete"
              name={`${base}.toComplete`}
              onChange={() => this.refresh()}
            />
          )}
        </div>
      </div>
    );
  };

  refresh = () => {
    const self = this;
    // Timeout so that the values are updated
    setTimeout(() => {
      const { values } = self.props;
      this.refreshContent(values);
    });
  };

  renderNewItemArray = (base: string, length: number) => {
    const { values } = this.props;
    const { nodeContent } = this.getInfoNode(base, values);
    let copyFirst = {};
    if (length > 0) {
      copyFirst = nodeContent && _.cloneDeep(nodeContent[0]);
    }

    if (copyFirst && copyFirst.type === 'Object') {
      return (
        <>
          <ModuleButton
            className={styles('button', 'left')}
            noMargin
            relative
            label="Add same as first"
            action={() => {
              copyFirst.label = `new ${length + 1}`;
              copyFirst.position = length;
              nodeContent.push(copyFirst);
              this.refreshContent(values);
            }}
          />
          {this.renderNewItem(base, length)}
        </>
      );
    }
    return this.renderNewItem(base, length);
  };

  renderField = (item: {}, base: string, baseParent: string) => {
    const { upload } = this.props;
    let type = item.type;
    type = type && type.toLowerCase();

    const toComplete = item.toComplete;

    const isOpen = item.open;
    const isHidden = item.hide;
    const isMatched = item.valueMatch?.length || item.labelMatch;

    if (isHidden) return false;
    if (
      type === 'input' ||
      type === 'textarea' ||
      type === 'wysiwyg' ||
      type === 'link_abs' ||
      type === 'link_rel' ||
      type === 'link_img' ||
      type === 'img' ||
      type === 'code'
    ) {
      let imageSrc;
      if (type.indexOf('img') >= 0 && item.src) {
        imageSrc = item?.src[config.cmsUploadImageKey] || item.src.getUrl || item.src.large;
      }
      return (
        <div
          className={styles(
            'field',
            toComplete && 'to-complete',
            isOpen && 'open',
            isMatched && 'is-matched',
          )}
        >
          {this.renderHead(item, base, baseParent)}
          {isOpen && (
            <div className={styles('content', 'test')}>
              {this.renderMeta(item, 'Value', base)}
              {type.indexOf('link') >= 0 && (
                <div className={styles('field-wrapper-container')}>
                  <Field
                    className={styles('url')}
                    component={Input}
                    fieldWrapperClassName={styles('field-wrapper')}
                    placeholder="Url"
                    withBorder
                    noMargin
                    disabled={item.lockedValue}
                    name={`${base}.link`}
                  />
                  <div
                    className={styles('icon-locker', item.lockedValue && 'active')}
                    onClick={() => this.lockItemValue(base, item)}
                  >
                    {item.lockedValue ? <FaLock /> : <FaUnlock />}
                  </div>
                </div>
              )}
              {type.indexOf('img') >= 0 && (
                <div className={styles('field-wrapper-container')}>
                  {imageSrc ? (
                    <div className={styles('field-link-wrapper')}>
                      <a href={imageSrc} target="_blank" rel="noopener noreferrer">
                        {imageSrc}
                      </a>
                    </div>
                  ) : (
                    <Field
                      className={styles('url')}
                      noMargin
                      name={`${base}.src`}
                      component={Input}
                      fieldWrapperClassName={styles('field-wrapper')}
                      placeholder="Img url"
                      disabled={item.lockedValue}
                      withBorder
                    />
                  )}
                  <div
                    className={styles('icon-locker', item.lockedValue && 'active')}
                    onClick={() => this.lockItemValue(base, item)}
                  >
                    {item.lockedValue ? <FaLock /> : <FaUnlock />}
                  </div>
                </div>
              )}
              {type !== 'img' && (
                <InputLanguage
                  upload={upload}
                  uploadUrl={item.url || 'pictures'}
                  lock={() => this.lockItemValue(base, item)}
                  locked={item.lockedValue}
                  matches={item.valueMatch}
                  matchClassName={styles('matched')}
                  inputProps={{
                    fieldWrapperClassName: styles('field-wrapper'),
                    valueClassName: 'small',
                    withBorder: true,
                    small: true,
                    // equivalent to 20 rows
                    autoResize: 400,
                  }}
                  disabled={item.lockedValue}
                  type={type}
                  noMargin
                  name={`${base}.content`}
                />
              )}
              {type.indexOf('img') >= 0 && !item.lockedValue && (
                <div className={styles('upload-container')}>
                  {item.src && typeof item.src === 'object' && (
                    <ModuleButton
                      small
                      noMargin
                      action={() => this.removeUploadedImage(base)}
                      className={styles('upload-container-button')}
                      relative
                      color="red"
                      label="Remove"
                    />
                  )}
                  <ModuleButton
                    small
                    noMargin
                    action={() => this.uploadImage(base)}
                    className={styles('upload-container-button')}
                    relative
                    label="Upload"
                    color={viewConfig.colorSubmit}
                  />
                </div>
              )}
            </div>
          )}
        </div>
      );
    }
    if (type === 'bool') {
      return (
        <div className={styles('field', 'value')}>
          <div className={styles('')}>
            {this.renderHead(item, base, baseParent)}
            {this.renderMeta(item, 'Value', base)}
          </div>
          <div className={styles('field-wrapper-value-container')}>
            <Field
              withBorder
              small
              noMargin
              name={`${base}.value`}
              placeholder="Value"
              activeClassName={styles('active-checkbox')}
              component={Checkbox}
              useBox
              fieldWrapperClassName={styles('field-wrapper')}
              disabled={item.lockedValue}
            />
            <div
              className={styles('icon-locker', item.lockedValue && 'active')}
              onClick={() => this.lockItemValue(base, item)}
            >
              {item.lockedValue ? <FaLock /> : <FaUnlock />}
            </div>
          </div>
        </div>
      );
    }
    if (type === 'value') {
      return (
        <div className={styles('field', 'value')}>
          <div className={styles('')}>
            {this.renderHead(item, base, baseParent)}
            {this.renderMeta(item, 'Value', base)}
          </div>
          <div className={styles('field-wrapper-value-container')}>
            <Field
              withBorder
              small
              noMargin
              name={`${base}.value`}
              placeholder="Value"
              component={Input}
              fieldWrapperClassName={styles('field-wrapper')}
              disabled={item.lockedValue}
            />
            <div
              className={styles('icon-locker', item.lockedValue && 'active')}
              onClick={() => this.lockItemValue(base, item)}
            >
              {item.lockedValue ? <FaLock /> : <FaUnlock />}
            </div>
          </div>
        </div>
      );
    }
    return <div>{`TODO : ${item.type}`}</div>;
  };

  renderGenericItem = (item: {}, base: string, baseParent: string) => {
    if (!item) return false;

    const isOpen = item.open;
    const isHidden = item.hide;
    const toComplete = item.toComplete;

    const isMatched = item.valueMatch?.length || item.labelMatch;

    if (item.type === 'Array' || item.type === 'array') {
      const list = this.orderEntries(item.content);
      return (
        !isHidden && (
          <div
            className={styles(
              'array',
              toComplete && 'to-complete',
              isOpen && 'open',
              isMatched && 'is-matched',
            )}
          >
            {this.renderHead(item, base, baseParent)}
            {isOpen && (
              <div className={styles('array-list', 'content')}>
                {this.renderMeta(item, 'Array', base)}
                {list &&
                  list.map(it => (
                    <div key={it.index}>
                      {this.renderGenericItem(it, `${base}.content[${it.index}]`, base)}
                    </div>
                  ))}
                <div className={styles('bottom')}>{this.renderNewItemArray(base, list.length)}</div>
              </div>
            )}
          </div>
        )
      );
    }
    if (item.type === 'Object' || item.type === 'object') {
      const list = this.orderEntries(item.content);

      return (
        !isHidden && (
          <div
            className={styles(
              'object',
              toComplete && 'to-complete',
              isOpen && 'open',
              isMatched && 'is-matched',
            )}
          >
            {this.renderHead(item, base, baseParent)}
            {isOpen && (
              <div className={styles('object-fields', 'content')}>
                {this.renderMeta(item, 'Object', base)}
                {list.map(it => {
                  if (it.key === config.keyNewContent) return false;
                  return (
                    <div key={it.key}>
                      {this.renderGenericItem(it, `${base}.content.${it.key}`, base)}
                    </div>
                  );
                })}
                <div className={styles('bottom')}>{this.renderNewItem(base, list.length)}</div>
              </div>
            )}
          </div>
        )
      );
    }
    if (item.type) return this.renderField(item, base, baseParent);
    return false;
  };

  renderHead = (item: {}, base: string, baseParent: string) => (
    <div className={styles('head')}>
      <div className={styles('head-info')}>
        <div
          className={styles('locker', item.locked && 'locked')}
          onClick={() => this.lockItem(base, item)}
        >
          {item.locked ? <FaLock /> : <FaUnlock />}
        </div>
        {item.type === 'Object' && <div className={styles('indic')}>{'{}'}</div>}
        {item.type === 'Array' && <div className={styles('indic')}>[]</div>}
        <div
          className={styles(
            'delete',
            item.type !== 'Object' && item.type !== 'Array' && 'space-right',
          )}
          onClick={() => this.deleteItem(baseParent, base, item.key)}
        >
          <FaTrash />
        </div>
      </div>

      <div className={styles('')} onClick={() => this.toggle(base)}>
        <Field
          fieldWrapperClassName={styles('field-wrapper', item.labelMatch && 'matched')}
          noMargin
          withBorder
          small
          name={`${base}.label`}
          placeholder="Label"
          disabled={item.locked}
          component={Input}
        />
      </div>
    </div>
  );

  orderEntries = (obj: {}) => {
    const newList = [];
    const entries = Object.entries(obj);
    for (let i = 0; i < entries.length; i++) {
      const entry = entries[i];
      const item = entry[1];

      if (item && typeof item === 'object' && item.position === undefined) {
        item.position = i + 1;
      }
      // key or index in arrays
      const key = entry[0];
      newList.push({
        ...item,
        // for arrays (allias for key)
        index: key,
        // add the key to the item (if not already presents)
        key,
      });
    }

    const ordered = _.orderBy(newList, item => Number.parseInt(item.position, 10), ['asc']);
    return ordered;
  };

  renderRoot = (content: {}) => {
    const list = this.orderEntries(content);

    return (
      <>
        {list.map(item => {
          if (item.key === config.keyNewContent) return false;
          return (
            <div key={item.key}>
              {this.renderGenericItem(
                item,
                `${config.cmsBaseName}.${item.key}`,
                config.cmsBaseName,
              )}
            </div>
          );
        })}
        <div className={styles('bottom')}>
          {this.renderNewItem(config.cmsBaseName, list.length, STRUCTURAL_TYPES)}
        </div>
      </>
    );
  };

  copyCurrent = base => {
    const { values, dialogSuccess, copyContent } = this.props;

    const { node, nodeContent } = this.getInfoNode(base, values);

    copyContent({
      type: node.type || 'Object',
      // removed the set all content new
      // content: setAllContentNew(clone(nodeContent)),
      content: clone(nodeContent),
    });

    dialogSuccess({
      data: 'Content copied',
    });
  };

  pasteCopy = base => {
    const { values, copy } = this.props;

    if (!copy) return;

    const clonedValues = clone(values);

    let newContent = clonedValues;

    const target = this.getInfoNode(base, clonedValues);
    if (target.node.type && target.node.type !== copy.type) return;

    // Array already exist : extension of the existing array
    // Important to use node.content
    if (target.node.type === 'Array' || target.node.type === 'array') {
      target.node.content = [...target.nodeContent, ...copy.content];
    }

    // If not array : 2 case
    // 1. Root => complety new content
    // 2. existing object that has to be extended
    else {
      const targetContent = {
        ...target.nodeContent,
        ...clone(copy.content),
      };
      // 1. Root
      if (!target.node.type) {
        newContent = {
          [config.cmsBaseName]: targetContent,
        };
      }
      // 2. exiting object
      else {
        target.node.content = targetContent;
      }
    }

    this.refreshContent(newContent);
  };

  renderNewItem = (base: string, length?: number, types?: {}[]) => {
    const { values, copy } = this.props;

    const { node, nodeContent, newItem } = this.getInfoNode(base, values);

    const firstItem = Object.values(nodeContent);
    const type = firstItem && firstItem[0] && firstItem[0].type;

    // force to keep same type level (object level vs field level)
    if (STRUCTURAL_VALUES.indexOf(type) >= 0) types = STRUCTURAL_TYPES;
    else if (FIELD_VALUES.indexOf(type) >= 0) types = FIELD_TYPES;
    else if (!types) types = ALL_TYPES;

    return (
      <>
        <Field
          className={styles('input')}
          name={`${base}.${config.keyNewContent}.type`}
          smallSuggestion
          component={CustomSelect}
          fieldWrapperClassName={styles('field-wrapper')}
          items={types}
          small
          filter
          noOrder
          withBorder
          noMargin
          placeholder="Type"
        />
        {(!newItem || newItem.type !== 'seo') && (
          <Field
            className={styles('input')}
            noMargin
            name={`${base}.${config.keyNewContent}.key`}
            withBorder
            small
            onKeyDown={e => this.onNewItemChange(e, base, length || 0)}
            component={Input}
            fieldWrapperClassName={styles('field-wrapper')}
            placeholder="Code key"
          />
        )}
        <ModuleButton
          small
          className={styles('button', 'left')}
          noMargin
          relative
          label="admin.buttons.add"
          action={() => this.addNewItem(base, length)}
          color={viewConfig.colorSubmit}
        />
        <ModuleButton
          small
          className={styles('button', 'left')}
          noMargin
          relative
          label="admin.buttons.copy"
          action={() => this.copyCurrent(base)}
          color="primary"
        />
        {copy && (copy.type === node.type || !node.type) && (
          <ModuleButton
            small
            className={styles('button')}
            noMargin
            relative
            label="admin.buttons.paste"
            action={() => this.pasteCopy(base)}
            color="orange"
          />
        )}
      </>
    );
  };

  saveAndClose = () => {
    const { values, handleSubmit } = this.props;

    const copy = clone(values[config.cmsBaseName]);

    const closeAll = current => {
      if (!current) return;
      const keys = Object.keys(current);
      for (let i = 0; i < keys.length; i += 1) {
        const key = keys[i];
        const elem = current[key];

        if (elem.open) elem.open = false;

        if (STRUCTURAL_VALUES.indexOf(elem.type) >= 0) closeAll(elem.content);
      }
    };
    closeAll(copy);

    this.refreshContent(copy);

    handleSubmit();
  };

  onNewItemChange = (event: KeyboardEvent, base: string, length: number) => {
    if (event.key === 'Enter') {
      event.preventDefault();
      this.addNewItem(base, length);
    }
  };

  render() {
    const { handleSubmit, form, values, completion, search } = this.props;

    if (!values) {
      return false;
    }

    return (
      <form className={styles('PageCmsForm')} onSubmit={handleSubmit}>
        <div className={styles('page-content')}>{this.renderRoot(values[config.cmsBaseName])}</div>
        <div className={styles('actions')}>
          <div className={styles('left')}>
            <ModuleButton
              className={styles('button')}
              noMargin
              relative
              small
              color={viewConfig.colorSubmit}
              label="admin.buttons.save"
              type="submit"
            />

            <ModuleButton
              className={styles('button')}
              noMargin
              relative
              small
              label="admin.buttons.closeSave"
              action={this.saveAndClose}
            />
          </div>

          <div className={styles('right')}>
            {search && search.filter && (
              <div className={styles('stats', 'search')}>
                <span> Result search : </span>
                <span>{search.totalMatch || 0}</span>
              </div>
            )}
            {completion && (
              <div className={styles('stats')}>
                <span>Completion : </span>
                <Percentage value={100 * (1 - completion.toComplete / completion.base)} />
              </div>
            )}
          </div>
        </div>
      </form>
    );
  }
}
