import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector, useStore } from 'react-redux';
import { AddOutlined, DeleteRounded } from '@mui/icons-material';

import { ALL_HUB_OPTION, ALL_OPTION_ID } from '../../../../constants';

import * as selectors from '../../../../redux/selectors';
import {
  attributeAllHubsSelector,
  attributeHubsSelector,
  attributeNameSelector,
  attributesKeyValuesSelector,
  fullAccessToStoreFieldsForValidation,
  hubOptionsSelector,
  schemeAttributeFormSelector,
  ssoCustomAttributesSelector,
} from '../../../../redux/selectors';
import {
  getHubOptionsAction,
  removeErrorByPropAction,
  setAction,
  setAttributesFormToInitialAction,
  setErrorByPropAttributeFormAction,
  setScrollToFieldNameAttributeFormAction,
  validateAttributeFields,
} from '../../../../redux/slices';
import { getInputPropsByName } from '@/modules/@common/Form/helpers';
import { addAllHubsOption } from '@/modules/sso/Editor/helpers/addAllHubsOption';

import { Form, FormContent, FormRow, FormSection, useFormSettings } from '@/modules/@common/Form';
import {
  Autocomplete,
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  IconButton,
  Stack,
  TextField,
} from '@/mui/components';

import styles from './AttributesForm.module.scss';

const NAME_MAX_LENGTH = 250;

function generateUniqueId() {
  const timestamp = Date.now();
  const randomPart = Math.random().toString(16).substring(2, 10);
  return `${timestamp}-${randomPart}`;
}

function AttributesForm(props) {
  const dispatch = useDispatch();
  const store = useStore();
  const { size } = useFormSettings();

  const ssoCustomAttributes = useSelector(ssoCustomAttributesSelector);

  const attributeName = useSelector(attributeNameSelector);
  const attributesKeyValues = useSelector(attributesKeyValuesSelector);
  const attributeHubs = useSelector(attributeHubsSelector);
  const attributeAllHubs = useSelector(attributeAllHubsSelector);
  const hubOptions = useSelector(hubOptionsSelector);

  const scheme = useSelector(selectors.schemeAttributeFormSelector);

  const handleSetState = (state) => dispatch(setAction(state));

  const handleAddAttributeFiled = () => {
    handleSetState({ attributesKeyValues: [...attributesKeyValues, ['', '']] });
  };
  const handleRemoveAttributeField = (index) => {
    const newAttributesKeyValues = [...attributesKeyValues.slice(0, index), ...attributesKeyValues.slice(index + 1)];
    handleSetState({ attributesKeyValues: newAttributesKeyValues });
  };
  const handleOnChangeAttributeKeyField = (index, value) => {
    const newAttributesKeyValues = attributesKeyValues.map((attribute, attributeIndex) =>
      attributeIndex === index ? [value, attribute[1]] : attribute,
    );
    handleSetState({ attributesKeyValues: newAttributesKeyValues });
  };
  const handleOnChangeAttributeValueField = (index, value) => {
    const newAttributesKeyValues = attributesKeyValues.map((attribute, attributeIndex) =>
      attributeIndex === index ? [attribute[0], value] : attribute,
    );
    handleSetState({ attributesKeyValues: newAttributesKeyValues });
  };

  const handleAdd = () => {
    const { attributeFormId, handleClose } = props;
    const exists = ssoCustomAttributes.some((attr) => attr.id === attributeFormId);

    let updatedAttributes;

    if (exists) {
      updatedAttributes = ssoCustomAttributes.map((attr) =>
        attr.id === attributeFormId
          ? {
              ...attr,
              name: attributeName,
              ssoCustomAttributesKeys: attributesKeyValues,
              ssoCustomAttributesHubs: attributeHubs,
              allHubs: attributeAllHubs,
            }
          : attr,
      );
    } else {
      const newAttribute = {
        id: generateUniqueId(),
        status: true,
        name: attributeName,
        ssoCustomAttributesKeys: attributesKeyValues,
        ssoCustomAttributesHubs: attributeHubs,
        allHubs: attributeAllHubs,
      };

      updatedAttributes = [...ssoCustomAttributes, newAttribute];
    }

    dispatch(setAction({ ssoCustomAttributes: updatedAttributes }));
    handleClose();
  };
  const handleAddStartProcess = () => {
    const state = store.getState();
    const allProps = fullAccessToStoreFieldsForValidation(state);
    const { validation, errorList } = validateAttributeFields(
      schemeAttributeFormSelector(state).map(({ fieldName }) => fieldName),
      allProps,
    );

    if (errorList.length) {
      const errorField = errorList[0];
      dispatch(setScrollToFieldNameAttributeFormAction(errorField.fieldName));
    } else {
      handleAdd();
    }

    dispatch(setErrorByPropAttributeFormAction(validation));
  };

  useEffect(() => {
    if (props.attributeFormId !== 'new') {
      const attribute = ssoCustomAttributes.find((attributeObject) => attributeObject.id === props.attributeFormId);
      dispatch(
        setAction({
          attributeName: attribute.name,
          attributesKeyValues: attribute.ssoCustomAttributesKeys,
          attributeHubs: attribute.allHubs ? [ALL_HUB_OPTION] : attribute.ssoCustomAttributesHubs,
          attributeAllHubs: attribute.allHubs,
        }),
      );
    }
  }, [props.attributeFormId]);

  useEffect(
    () => () => {
      dispatch(setAttributesFormToInitialAction());
    },
    [],
  );

  return (
    <Dialog open={props.attributeFormId} onClose={props.handleClose} maxWidth="xl">
      <DialogTitle onClose={props.handleClose}>Assign Users to Hubs</DialogTitle>
      <DialogContent>
        <Form>
          <FormContent>
            <FormSection>
              <FormRow label="Rule Name">
                <TextField
                  size={size}
                  placeholder="Rule Name"
                  value={attributeName}
                  inputProps={{ maxLength: NAME_MAX_LENGTH }}
                  onChange={(e) => handleSetState({ attributeName: e.target.value })}
                  {...getInputPropsByName(scheme, ['attributeName'])}
                  onFocus={() => dispatch(removeErrorByPropAction(['attributeName']))}
                />
              </FormRow>

              <FormRow
                label="Attributes"
                tooltip="Key and value pairs define custom attributes for assigning a user to a hub. Having more than one attribute adds a logical AND in-between attributes."
                multiline
              >
                {attributesKeyValues.map((_, index) => (
                  <FormRow fullWidth key={index} multiline>
                    <Stack direction="row" gap={1} fullWidth className={styles.AttributesFieldRow}>
                      <TextField
                        size={size}
                        placeholder="Add attribute key"
                        value={attributesKeyValues[index][0]}
                        onChange={(e) => handleOnChangeAttributeKeyField(index, e.target.value)}
                        {...getInputPropsByName(scheme, ['attributesKeyValues', index, 'key'])}
                        onFocus={() => dispatch(removeErrorByPropAction(['attributesKeyValues', index, 'key']))}
                      />
                      <TextField
                        size={size}
                        placeholder="Add attribute value"
                        value={attributesKeyValues[index][1]}
                        onChange={(e) => handleOnChangeAttributeValueField(index, e.target.value)}
                        {...getInputPropsByName(scheme, ['attributesKeyValues', index, 'value'])}
                        onFocus={() => dispatch(removeErrorByPropAction(['attributesKeyValues', index, 'value']))}
                      />
                      {attributesKeyValues.length > 1 && (
                        <div className={styles.AttributesDelete}>
                          <IconButton size={size} component="span" onClick={() => handleRemoveAttributeField(index)}>
                            <DeleteRounded />
                          </IconButton>
                        </div>
                      )}
                    </Stack>
                  </FormRow>
                ))}
                <FormRow justifyContent="flex-end" fullWidth>
                  <Button
                    size={size}
                    variant="text"
                    color="primary"
                    label="ADD OPTION"
                    startIcon={<AddOutlined />}
                    onClick={handleAddAttributeFiled}
                  >
                    Add Attribute
                  </Button>
                </FormRow>
              </FormRow>

              <FormRow label="Hubs">
                <Stack fullWidth>
                  <Autocomplete
                    fullWidth
                    multiple
                    value={attributeHubs || []}
                    options={addAllHubsOption(hubOptions) || []}
                    optionValueKey="id"
                    optionLabelKey="name"
                    loading={!hubOptions}
                    size={size}
                    filterSelectedOptions
                    disableClearable
                    filterOptions={(options) => {
                      const hasAllOption = attributeHubs.some((option) => option.id === ALL_OPTION_ID);
                      return hasAllOption ? [] : options;
                    }}
                    onChange={(e, selected) => {
                      const hasAllOption = selected.some((option) => option.id === ALL_OPTION_ID);
                      handleSetState({
                        attributeAllHubs: hasAllOption,
                        attributeHubs: hasAllOption ? [ALL_HUB_OPTION] : selected,
                      });
                    }}
                    onOpen={() => {
                      dispatch(getHubOptionsAction(''));
                    }}
                    onInputChange={(e, searchText) => dispatch(getHubOptionsAction(searchText))}
                    renderInput={(params) => (
                      <TextField
                        {...params}
                        value=""
                        placeholder="Select Hub"
                        {...getInputPropsByName(scheme, ['attributeHubs'])}
                        onFocus={() => dispatch(removeErrorByPropAction(['attributeHubs']))}
                      />
                    )}
                  />
                </Stack>
              </FormRow>
            </FormSection>
          </FormContent>
        </Form>
      </DialogContent>
      <DialogActions>
        <Button size="small" variant="outlined" color="primary" onClick={props.handleClose}>
          Cancel
        </Button>
        <Button size="small" variant="contained" color="primary" onClick={handleAddStartProcess}>
          Add
        </Button>
      </DialogActions>
    </Dialog>
  );
}

AttributesForm.propTypes = {
  attributeFormId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  handleClose: PropTypes.func.isRequired,
};

export default AttributesForm;
