import React, { Fragment, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import classNames from 'clsx';
import { AddRounded, DeleteRounded, InfoOutlined, SearchRounded } from '@mui/icons-material';

import {
  CONDITION_OPTIONS,
  FIRST_RULE_SELECT_INDEX,
  FIRST_RULE_SHARE_WITH_INDEX,
  MAX_RULE_SELECT_INDEX,
  MAX_RULE_SHARE_WITH_INDEX,
  RULE_TYPE_ALL_MY_VIDEO,
  RULE_TYPE_LABELS,
  RULE_TYPE_OPTIONS,
  RULE_TYPE_SOURCES,
  RULE_TYPE_WORDS_IN_TITLE,
  SHARE_WITH_TYPE_ALL_RELATED_USERS,
  SHARE_WITH_TYPE_HUBS,
  SHARE_WITH_TYPE_OPTIONS,
  SHARE_WITH_TYPE_USERS,
} from '../constants';
import { GET_PERSONAL_SETTING, POST_PERSONAL_SETTING, PUT_PERSONAL_SETTING } from '@/modules/@common/acl/constants';

import * as calculationsFromStore from '../helpers/calculationsFromStore';
import { hubsOptionsSelector, searchSelector, sourcesOptionsSelector, usersOptionsSelector } from '../redux/selectors';
import {
  getHubsOptionsAction,
  getRulesAction,
  getSourcesOptionAction,
  getUsersOptionsAction,
  setModuleStateAction,
} from '../redux/slices';
import { hasPermission } from '@/modules/@common/user/helpers';
import { getUserPermissionsSelector } from '@/modules/@common/user/redux/selectors';

import {
  Form,
  FormContent,
  FormGroup,
  FormGroupTitle,
  FormRow,
  FormRowItem,
  FormSection,
} from '@/modules/@common/Form';
import CollapsedContainer from './CollapsedContainer';
import Empty from './Empty';
import useLogic from './useLogic';
import UsersAutocomplete from './UsersAutocomplete';
import {
  Autocomplete,
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  IconButton,
  InputAdornment,
  InputLabel,
  MenuItem,
  Select,
  Stack,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Tooltip,
  Typography,
} from '@/mui/components';

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

function UserRulesSettings() {
  const dispatch = useDispatch();
  const search = useSelector(searchSelector);

  const rulesBySearch = useSelector((state) => calculationsFromStore.rulesBySearch(state));
  const shouldShowDuplicateNameError = useSelector(calculationsFromStore.shouldShowDuplicateNameError);
  const shouldDisableCreateNewRule = useSelector((state) => calculationsFromStore.shouldDisableCreateNewRule(state));
  const shouldDisabledSave = useSelector((state) => calculationsFromStore.shouldDisabledSave(state));
  const isDirty = useSelector((state) => calculationsFromStore.isDirty(state));
  const sourcesOptions = useSelector(sourcesOptionsSelector);
  const usersOptions = useSelector(usersOptionsSelector);
  const hubsOptions = useSelector(hubsOptionsSelector);
  const userPermissions = useSelector(getUserPermissionsSelector);

  const [ruleToDelete, setRuleToDelete] = useState(null);

  const {
    // collapsed container handlers
    handleRuleAddNew,
    handleRuleTitleChange,
    handleRuleToggleTitleEditMode,
    handleRuleToggleOpen,
    handleRulesDeleteShowConfirm,
    handleRuleDelete,
    // rule select type handlers
    handleRuleSelectChangeType,
    handleRuleSelectDelete,
    handleRuleSelectAdd,
    handleAutocompleteRuleSelectOnChange,
    handleRuleSelectChangeCondition,
    // rule shareWith handlers
    handleShareWithChangeType,
    handleShareWithDelete,
    handleShareWithAdd,
    handleAutocompleteShareWithOnChange,
    // save/cancel rules
    handleRuleSave,
    handleRuleCancel,
  } = useLogic({ setRuleToDelete });

  useEffect(() => {
    if (hasPermission(GET_PERSONAL_SETTING, userPermissions)) {
      dispatch(getRulesAction());
    }
  }, []);

  return (
    <div className={styles.Wrapper}>
      <Stack spacing={0} direction="column" fullWidth alignItems="flex-start" className={styles.Title}>
        <Typography component="div" variant="h6">
          Personal Settings
        </Typography>
        <Typography component="div" variant="body2">
          <Stack spacing={1} direction="row" alignItems="center">
            <div>Set automated rules for your owned videos</div>
            <Tooltip
              title={
                'Owned videos are videos uploaded by you or recorded meetings ' +
                "where you're the host, excluding syndication videos"
              }
            >
              <InfoOutlined fontSize="small" color="info.main" />
            </Tooltip>
          </Stack>
        </Typography>
      </Stack>
      <Stack
        spacing={1}
        fullWidth
        direction="row"
        alignItems="center"
        justifyContent="space-between"
        className={styles.Controls}
      >
        <div className={styles.Search}>
          <TextField
            id="search"
            size="small"
            variant="outlined"
            value={search}
            onChange={({ target }) => dispatch(setModuleStateAction({ search: target.value }))}
            placeholder="Search"
            disabled={shouldDisableCreateNewRule}
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton onClick={() => null}>
                    <SearchRounded />
                  </IconButton>
                </InputAdornment>
              ),
            }}
          />
        </div>
        {hasPermission(POST_PERSONAL_SETTING, userPermissions) && (
          <Button
            size="small"
            variant="contained"
            color="primary"
            startIcon={<AddRounded />}
            disabled={shouldDisableCreateNewRule}
            onClick={handleRuleAddNew}
          >
            Create New Rule
          </Button>
        )}
      </Stack>
      {!rulesBySearch?.length && <Empty hasSearchQuery={!!search} />}

      {!!rulesBySearch?.length && (
        <Form>
          <FormContent>
            <FormSection>
              {rulesBySearch?.map((rule) => {
                const hasNameDuplicate = shouldShowDuplicateNameError(rule.ruleName, rule.uiIsSaved, rule.uiIndex);

                const notCanEdit = !hasPermission(PUT_PERSONAL_SETTING, userPermissions) && !!rule.initialFromApi;

                return (
                  <FormRow key={rule.uiIndex} fullWidth>
                    <CollapsedContainer
                      expanded={rule.uiIsOpen}
                      title={rule.ruleName}
                      disabled={notCanEdit}
                      hasNameDuplicate={hasNameDuplicate}
                      onToggleTitleEditMode={() => handleRuleToggleTitleEditMode(rule.uiIndex)}
                      onTitleChange={(title) => handleRuleTitleChange(title, rule.uiIndex)}
                      onDelete={() => handleRulesDeleteShowConfirm(rule)}
                      onToggleOpen={() => handleRuleToggleOpen(rule.uiIndex)}
                    >
                      <FormGroup>
                        <FormGroupTitle>Select</FormGroupTitle>
                        <FormGroup elevation={0}>
                          {rule.ruleSelectType.map((ruleSelect, ruleSelectTypeIndex) => {
                            const options = RULE_TYPE_OPTIONS.filter((option) =>
                              rule.ruleSelectType.every((o) => o.type !== option.value),
                            ).filter((option) =>
                              ruleSelectTypeIndex > FIRST_RULE_SELECT_INDEX
                                ? option.value !== RULE_TYPE_ALL_MY_VIDEO
                                : true,
                            );

                            const extraAutocompleteProps = {
                              [RULE_TYPE_WORDS_IN_TITLE]: {
                                helperText: 'Please type a word and press enter',
                                options: [],
                                onChange: (e, value) => {
                                  handleAutocompleteRuleSelectOnChange(value, rule.uiIndex, ruleSelectTypeIndex);
                                },
                              },
                              [RULE_TYPE_LABELS]: {
                                helperText: 'Please type a label and press enter',
                                options: [],
                                onChange: (e, value) => {
                                  handleAutocompleteRuleSelectOnChange(value, rule.uiIndex, ruleSelectTypeIndex);
                                },
                              },
                              [RULE_TYPE_SOURCES]: {
                                filterSelectedOptions: true,
                                options: sourcesOptions || [],
                                loading: !sourcesOptions,
                                getOptionLabel: (option) => option.label || '',
                                isOptionEqualToValue: (option, value) => option.value === value.value,
                                onChange: (e, value) => {
                                  handleAutocompleteRuleSelectOnChange(value, rule.uiIndex, ruleSelectTypeIndex);
                                },
                                onOpen: () => dispatch(getSourcesOptionAction('')),
                                onInputChange: ({ target }) => dispatch(getSourcesOptionAction(target.value)),
                              },
                            }[ruleSelect.type];

                            return (
                              <Fragment key={ruleSelect.type}>
                                {ruleSelectTypeIndex !== FIRST_RULE_SELECT_INDEX && (
                                  <FormRow fullWidth justifyContent="center">
                                    <ToggleButtonGroup
                                      size="xSmall"
                                      value={ruleSelect.condition}
                                      exclusive
                                      onChange={(event, value) => {
                                        handleRuleSelectChangeCondition(value, rule.uiIndex, ruleSelectTypeIndex);
                                      }}
                                    >
                                      {CONDITION_OPTIONS.map((condition) => (
                                        <ToggleButton key={condition.value} value={condition.value}>
                                          {condition.label}
                                        </ToggleButton>
                                      ))}
                                    </ToggleButtonGroup>
                                  </FormRow>
                                )}
                                <FormGroup
                                  elevation={rule.ruleSelectType.length > 1 ? 2 : 0}
                                  className={classNames(styles.SubGroup, {
                                    [styles.SubGroup___highlight]: rule.ruleSelectType.length > 1,
                                  })}
                                >
                                  <FormRow fullWidth>
                                    <FormControl component={FormRowItem} itemsInRow={4}>
                                      {ruleSelectTypeIndex === FIRST_RULE_SELECT_INDEX && (
                                        <InputLabel size="small" required>
                                          Required
                                        </InputLabel>
                                      )}
                                      <Select
                                        fullWidth
                                        size="small"
                                        placeholder="Select videos"
                                        required={ruleSelectTypeIndex === FIRST_RULE_SELECT_INDEX}
                                        label={ruleSelectTypeIndex === FIRST_RULE_SELECT_INDEX ? 'Required' : ''}
                                        value={ruleSelect.type || -1}
                                        disabled={notCanEdit}
                                        onChange={({ target }) => {
                                          handleRuleSelectChangeType(target.value, rule.uiIndex, ruleSelectTypeIndex);
                                        }}
                                      >
                                        <MenuItem value={-1} className={styles.Hidden}>
                                          Select Videos
                                        </MenuItem>
                                        {RULE_TYPE_OPTIONS.map((type) => {
                                          const disabled = !options.some((opt) => opt.value === type.value);

                                          return (
                                            <MenuItem
                                              className={disabled ? styles.Hidden : ''}
                                              key={type.value}
                                              value={type.value}
                                            >
                                              {type.label}
                                            </MenuItem>
                                          );
                                        })}
                                      </Select>
                                    </FormControl>
                                    <Stack direction="row" spacing={2} fullWidth>
                                      {ruleSelect.type && ruleSelect.type !== RULE_TYPE_ALL_MY_VIDEO && (
                                        <Autocomplete
                                          fullWidth
                                          multiple
                                          disableClearable
                                          freeSolo={ruleSelect.type !== RULE_TYPE_SOURCES}
                                          size="small"
                                          value={ruleSelect.value}
                                          optionValueKey="label"
                                          disabled={notCanEdit}
                                          loadingText={
                                            <Typography variant="body2" color="text.secondary" fontWeight={400}>
                                              Loading...
                                            </Typography>
                                          }
                                          renderInput={(params) => (
                                            <TextField
                                              {...params}
                                              placeholder={ruleSelect.type === RULE_TYPE_SOURCES ? 'Select' : 'Type'}
                                              helperText={extraAutocompleteProps.helperText}
                                            />
                                          )}
                                          {...extraAutocompleteProps}
                                        />
                                      )}
                                      {rule.ruleSelectType.length > 1 && (
                                        <IconButton
                                          size="small"
                                          color="neutral"
                                          disabled={notCanEdit}
                                          onClick={() => handleRuleSelectDelete(rule.uiIndex, ruleSelectTypeIndex)}
                                        >
                                          <DeleteRounded />
                                        </IconButton>
                                      )}
                                    </Stack>
                                  </FormRow>
                                  {ruleSelectTypeIndex === rule.ruleSelectType.length - 1 &&
                                    !notCanEdit &&
                                    ruleSelect.type &&
                                    ruleSelect.type !== RULE_TYPE_ALL_MY_VIDEO &&
                                    ruleSelectTypeIndex !== MAX_RULE_SELECT_INDEX && (
                                      <FormRow>
                                        <Button
                                          variant="outlined"
                                          color="primary"
                                          size="small"
                                          onClick={() => handleRuleSelectAdd(rule.uiIndex, options[0].value)}
                                          startIcon={<AddRounded />}
                                        >
                                          Add Select Rule
                                        </Button>
                                      </FormRow>
                                    )}
                                </FormGroup>
                              </Fragment>
                            );
                          })}
                        </FormGroup>
                        <FormGroupTitle>Share With</FormGroupTitle>
                        <FormGroup elevation={0}>
                          {rule.ruleShareWithType.map((ruleSelect, ruleSelectTypeIndex) => {
                            const shouldShowPlusButton =
                              ruleSelect.type &&
                              ruleSelect.type !== SHARE_WITH_TYPE_ALL_RELATED_USERS &&
                              ruleSelectTypeIndex !== MAX_RULE_SHARE_WITH_INDEX;

                            const options = SHARE_WITH_TYPE_OPTIONS.filter((option) =>
                              rule.ruleShareWithType.every((o) => o.type !== option.value),
                            ).filter((option) =>
                              ruleSelectTypeIndex > FIRST_RULE_SHARE_WITH_INDEX
                                ? option.value !== SHARE_WITH_TYPE_ALL_RELATED_USERS
                                : true,
                            );

                            return (
                              <FormGroup
                                key={ruleSelect.type}
                                elevation={rule.ruleShareWithType.length > 1 ? 2 : 0}
                                className={classNames(styles.SubGroup, {
                                  [styles.SubGroup___highlight]: rule.ruleShareWithType.length > 1,
                                })}
                              >
                                <FormRow fullWidth>
                                  <FormControl component={FormRowItem} itemsInRow={4}>
                                    {ruleSelectTypeIndex === FIRST_RULE_SHARE_WITH_INDEX && (
                                      <InputLabel size="small" required>
                                        Required
                                      </InputLabel>
                                    )}
                                    <Select
                                      size="small"
                                      enableRemove={rule.ruleShareWithType.length > 1}
                                      value={ruleSelect.type || -1}
                                      disabled={notCanEdit}
                                      required={ruleSelectTypeIndex === FIRST_RULE_SHARE_WITH_INDEX}
                                      label={ruleSelectTypeIndex === FIRST_RULE_SHARE_WITH_INDEX ? 'Required' : ''}
                                      onChange={({ target }) => {
                                        handleShareWithChangeType(target.value, rule.uiIndex, ruleSelectTypeIndex);
                                      }}
                                    >
                                      <MenuItem value={-1} className={styles.Hidden}>
                                        Select with whom to share
                                      </MenuItem>
                                      {SHARE_WITH_TYPE_OPTIONS.map((type) => {
                                        const disabled = !options.some((opt) => opt.value === type.value);

                                        return (
                                          <MenuItem
                                            className={disabled ? styles.Hidden : ''}
                                            key={type.value}
                                            value={type.value}
                                          >
                                            {type.label}
                                          </MenuItem>
                                        );
                                      })}
                                    </Select>
                                  </FormControl>
                                  <Stack
                                    spacing={2}
                                    fullWidth
                                    direction="row"
                                    alignItems="flex-start"
                                    justifyContent="flex-end"
                                  >
                                    {ruleSelect.type && (
                                      <>
                                        {ruleSelect.type === SHARE_WITH_TYPE_USERS && (
                                          <UsersAutocomplete
                                            options={usersOptions}
                                            users={ruleSelect.value}
                                            disabled={notCanEdit}
                                            onGetOptions={(searchText = '') => {
                                              dispatch(getUsersOptionsAction(searchText));
                                            }}
                                            onChange={(value) => {
                                              handleAutocompleteShareWithOnChange(
                                                value,
                                                rule.uiIndex,
                                                ruleSelectTypeIndex,
                                              );
                                            }}
                                          />
                                        )}

                                        {ruleSelect.type === SHARE_WITH_TYPE_HUBS && (
                                          <Autocomplete
                                            fullWidth
                                            multiple
                                            size="small"
                                            optionValueKey="label"
                                            loadingText={
                                              <Typography variant="body2" color="text.secondary" fontWeight={400}>
                                                Loading...
                                              </Typography>
                                            }
                                            renderInput={(params) => <TextField {...params} placeholder="Select" />}
                                            filterSelectedOptions
                                            disableClearable
                                            value={ruleSelect.value}
                                            options={hubsOptions || []}
                                            loading={!hubsOptions}
                                            getOptionLabel={(option) => option.label || ''}
                                            isOptionEqualToValue={(option, value) => option.value === value.value}
                                            disabled={notCanEdit}
                                            onChange={(e, value) => {
                                              handleAutocompleteShareWithOnChange(
                                                value,
                                                rule.uiIndex,
                                                ruleSelectTypeIndex,
                                              );
                                            }}
                                            onOpen={() => dispatch(getHubsOptionsAction(''))}
                                            onInputChange={({ target }) => dispatch(getHubsOptionsAction(target.value))}
                                          />
                                        )}
                                      </>
                                    )}
                                    {rule.ruleShareWithType.length > 1 && (
                                      <IconButton
                                        size="small"
                                        color="neutral"
                                        disabled={notCanEdit}
                                        onClick={() => handleShareWithDelete(rule.uiIndex, ruleSelectTypeIndex)}
                                      >
                                        <DeleteRounded />
                                      </IconButton>
                                    )}
                                  </Stack>
                                </FormRow>
                                {ruleSelectTypeIndex === rule.ruleShareWithType.length - 1 &&
                                  shouldShowPlusButton &&
                                  !notCanEdit && (
                                    <FormRow>
                                      <Button
                                        variant="outlined"
                                        color="primary"
                                        size="small"
                                        onClick={() => handleShareWithAdd(rule.uiIndex, options[0].value)}
                                        startIcon={<AddRounded />}
                                      >
                                        Add Share With Rule
                                      </Button>
                                    </FormRow>
                                  )}
                              </FormGroup>
                            );
                          })}
                        </FormGroup>

                        {hasPermission(POST_PERSONAL_SETTING, userPermissions) && (
                          <FormRow fullWidth justifyContent="flex-end">
                            {!!rule.initialFromApi && (
                              <Button
                                variant="outlined"
                                size="small"
                                color="primary"
                                shape="rounded"
                                disabled={!isDirty(rule.uiIndex)}
                                onClick={() => handleRuleCancel(rule.uiIndex)}
                              >
                                Cancel
                              </Button>
                            )}
                            <Button
                              variant="contained"
                              size="small"
                              color="primary"
                              shape="rounded"
                              disabled={shouldDisabledSave(rule.uiIndex) || hasNameDuplicate || !isDirty(rule.uiIndex)}
                              onClick={() => handleRuleSave(rule.uiIndex, rule.name)}
                            >
                              Save
                            </Button>
                          </FormRow>
                        )}
                      </FormGroup>
                    </CollapsedContainer>
                  </FormRow>
                );
              })}
            </FormSection>
          </FormContent>
        </Form>
      )}
      {!!ruleToDelete && (
        <Dialog open={!!ruleToDelete} onClose={() => setRuleToDelete(null)} maxWidth="sm">
          <DialogTitle onClose={() => setRuleToDelete(null)}>Warning</DialogTitle>
          <DialogContent>{`Are you sure you would like to delete the rule "${ruleToDelete?.ruleName}"?`}</DialogContent>
          <DialogActions>
            <Button size="small" variant="outlined" color="primary" onClick={() => setRuleToDelete(null)}>
              Cancel
            </Button>
            <Button
              size="small"
              variant="contained"
              color="primary"
              onClick={() => handleRuleDelete(ruleToDelete.uiIndex)}
            >
              Delete
            </Button>
          </DialogActions>
        </Dialog>
      )}
    </div>
  );
}

export default UserRulesSettings;
