// Copyright 2020 Northern.tech AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
import { useState } from 'react';

import { Autocomplete, FormHelperText, TextField } from '@mui/material';
import { createFilterOptions } from '@mui/material/useAutocomplete';

import DocsLink from '@northern.tech/common-ui/DocsLink';
import InfoText from '@northern.tech/common-ui/InfoText';
import { UNGROUPED_GROUP } from '@northern.tech/store/constants';
import { fullyDecodeURI } from '@northern.tech/utils/helpers';
import validator from 'validator';

const filter = createFilterOptions();

const NAME_LENGTH_LIMIT = 256;

export const validateGroupName = (encodedName: string, groups = [], selectedDevices = [], isCreationDynamic) => {
  const name = fullyDecodeURI(encodedName);
  let invalid = false;
  let errorText = '';
  const isModification = name.length && groups.some(group => decodeURIComponent(group) === name);
  if (!name && !isModification) {
    invalid = true;
  } else if (!validator.isWhitelisted(name, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.')) {
    invalid = true;
    errorText = 'Valid characters are a-z, A-Z, 0-9, ., _ and -';
  } else if (name.length > NAME_LENGTH_LIMIT) {
    invalid = true;
    errorText = `Name must be at most ${NAME_LENGTH_LIMIT} characters long`;
  } else if (selectedDevices.length && selectedDevices.every(({ group }) => group === name)) {
    invalid = true;
    errorText = `${name} is the same group the selected devices are already in`;
  } else if (isModification && isCreationDynamic) {
    invalid = true;
    errorText = 'A group with the same name already exists';
  } else if (name === UNGROUPED_GROUP.name) {
    invalid = true;
    errorText = `A group with the name ${name} is created automatically`;
  }
  return { errorText: errorText, invalid, isModification, name };
};

const GroupOption = (props, option) => <li {...props}>{option.title}</li>;

export const GroupDefinition = ({ isCreationDynamic, groups, newGroup, onInputChange, selectedDevices }) => {
  const [errorText, setErrorText] = useState('');

  const validateName = (encodedName: string) => {
    const { errorText: error, invalid, isModification, name } = validateGroupName(encodedName, groups, selectedDevices, isCreationDynamic);
    setErrorText(error);
    onInputChange(invalid, name, isModification);
  };

  const mappedGroups = groups.map(group => ({ value: group, title: group }));
  return (
    <>
      <Autocomplete
        id="group-creation-selection"
        className="margin-top-x-small"
        autoSelect
        freeSolo
        filterSelectedOptions
        filterOptions={(options, params) => {
          const filtered = filter(options, params);
          if (
            params.inputValue !== '' &&
            !groups.some(group => decodeURIComponent(group) === params.inputValue) &&
            (filtered.length !== 1 || (filtered.length === 1 && filtered[0].title !== params.inputValue))
          ) {
            filtered.push({
              inputValue: params.inputValue,
              title: `Create "${params.inputValue}" group`
            });
          }
          return filtered;
        }}
        getOptionLabel={option => {
          if (typeof option === 'string') {
            return option;
          }
          if (option.inputValue) {
            return option.inputValue;
          }
          return option.title;
        }}
        handleHomeEndKeys
        inputValue={newGroup}
        options={mappedGroups}
        onInputChange={(e, newValue) => validateName(newValue)}
        renderInput={params => <TextField {...params} label="Select a group, or type to create new" />}
        renderOption={GroupOption}
      />
      <FormHelperText>{errorText}</FormHelperText>
      {isCreationDynamic && (
        <InfoText>
          Note: individual devices can&apos;t be added to dynamic groups.
          <br />
          <DocsLink path="overview/device-group" title="Learn more about static vs. dynamic groups" />
        </InfoText>
      )}
    </>
  );
};

export default GroupDefinition;
