/**
 * IdWidget component.
 * @module components/manage/Widgets/IdWidget
 */

import { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { Input } from 'semantic-ui-react';
import compact from 'lodash/compact';
import concat from 'lodash/concat';
import map from 'lodash/map';
import union from 'lodash/union';
import uniq from 'lodash/uniq';

import { defineMessages, useIntl } from 'react-intl';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
import config from '@plone/volto/registry';
import { getQuerystring } from '@plone/volto/actions/querystring/querystring';

const messages = defineMessages({
  reservedId: {
    id: "This is a reserved name and can't be used",
    defaultMessage: "This is a reserved name and can't be used",
  },
  invalidCharacters: {
    id: 'Only 7-bit bytes characters are allowed. Cannot contain uppercase letters, special characters: <, >, &, #, /, ?, or others that are illegal in URLs. Cannot start with: _, aq_, @@, ++. Cannot end with __. Cannot be: request,contributors, ., .., "". Cannot contain new lines.',
    defaultMessage:
      'Only 7-bit bytes characters are allowed. Cannot contain uppercase letters, special characters: <, >, &, #, /, ?, or others that are illegal in URLs. Cannot start with: _, aq_, @@, ++. Cannot end with __. Cannot be: request,contributors, ., .., "". Cannot contain new lines.',
  },
});

const IdWidget = (props) => {
  const {
    id,
    onClick,
    icon,
    iconAction,
    minLength,
    maxLength,
    onBlur,
    value,
    focus,
    isDisabled,
    placeholder,
    onChange,
  } = props;

  const intl = useIntl();
  const dispatch = useDispatch();
  const ref = useRef();
  const indexes = useSelector((state) => state.querystring.indexes);

  const [errors, setError] = useState([]);
  const [reservedIds] = useState(
    compact(
      uniq(
        union(
          config.settings.reservedIds,
          map(config.settings.nonContentRoutes, (route) =>
            String(route).replace(/[^a-z-]/g, ''),
          ),
        ),
      ),
    ),
  );
  const fieldValidation = (value) => {
    const error = [];

    // Check reserved id's
    if (reservedIds.indexOf(value) !== -1) {
      error.push(intl.formatMessage(messages.reservedId));
    }

    // Check invalid characters
    if (
      // eslint-disable-next-line no-control-regex
      !/^(?!.*\\)(?!\+\+)(?!@@)(?!.*request)(?!.*contributors)(?!aq_)(?!.*__)(?!_)(?!((^|\/)\.\.?($|\/)|^"\s*"$))(?!.*[A-Z])(?:(?![\r\n<>/?&#\x00-\x1F\x7F])['\x00-\x7F\u0080-\uFFFF. _])*$/.test(
        value,
      )
    ) {
      error.push(intl.formatMessage(messages.invalidCharacters));
    }

    // Check indexes
    if (value in indexes) {
      error.push(intl.formatMessage(messages.reservedId));
    }

    setError(error);
  };

  useEffect(
    () => {
      if (focus) ref.current.focus();

      dispatch(getQuerystring());
      fieldValidation(value);
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [focus, value, dispatch],
  );

  const handleChange = ({ target }) => {
    fieldValidation(target.value);
    onChange(id, target.value === '' ? undefined : target.value);
  };

  const handleBlur = ({ target }) => {
    fieldValidation(target.value);
    onBlur(id, target.value === '' ? undefined : target.value);
  };

  props = {
    ...props,
    error: concat(props.error, errors),
  };

  return (
    <FormFieldWrapper {...props} className="text">
      <Input
        id={`field-${id}`}
        name={id}
        value={value || ''}
        disabled={isDisabled}
        icon={icon || null}
        placeholder={placeholder}
        onChange={handleChange}
        onBlur={handleBlur}
        onClick={() => onClick()}
        ref={ref}
        minLength={minLength || null}
        maxLength={maxLength || null}
      />
      {icon && iconAction && (
        <button className={`field-${id}-action-button`} onClick={iconAction}>
          <Icon name={icon} size="18px" />
        </button>
      )}
    </FormFieldWrapper>
  );
};

export default IdWidget;

IdWidget.propTypes = {
  id: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  description: PropTypes.string,
  required: PropTypes.bool,
  error: PropTypes.arrayOf(PropTypes.string),
  value: PropTypes.string,
  focus: PropTypes.bool,
  onChange: PropTypes.func,
  onBlur: PropTypes.func,
  onClick: PropTypes.func,
  onEdit: PropTypes.func,
  onDelete: PropTypes.func,
  icon: PropTypes.shape({
    xmlns: PropTypes.string,
    viewBox: PropTypes.string,
    content: PropTypes.string,
  }),
  iconAction: PropTypes.func,
  minLength: PropTypes.number,
  maxLength: PropTypes.number,
  wrapped: PropTypes.bool,
  placeholder: PropTypes.string,
};

IdWidget.defaultProps = {
  description: null,
  required: false,
  error: [],
  value: null,
  onChange: () => {},
  onBlur: () => {},
  onClick: () => {},
  onEdit: null,
  onDelete: null,
  focus: false,
  icon: null,
  iconAction: null,
  minLength: null,
  maxLength: null,
};
