import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import dayjs from 'dayjs';
import { useRouter } from 'next/router';

import { STATUSES_ACTIVE, STATUSES_INACTIVE } from '../../../../List/constants';
import { HUB_ADMIN_ROLE, OPTION_ALL, OPTION_ALL_ID } from '../../../constants';
import { ACCOUNT, API, EXTERNAL, INTERNAL } from '@/modules/@common/user/constants/rolesType';

import { getCanReadOnly } from '../../../helpers/getRestrictions';
import * as selectors from '../../../redux/selectors';
import {
  createDepartmentAction,
  getAccountOptionsAction,
  getContentOwnersOptionsAction,
  getDepartmentOptionsAction,
  getRoleOptionsAction,
  getTimezoneOptionsAction,
  removeErrorByPropAction,
  setAction,
} from '../../../redux/slices';
import { getInputPropsByName } from '@/modules/@common/Form/helpers';
import { deepClone } from '@/modules/@common/helpers';
import {
  getPublisherIdsSelector,
  getUserAccountIdSelector,
  getUserAccountSelector,
  getUserPermissionsSelector,
  getUserRoleTypeSelector,
  getUserTimezoneSelector,
} from '@/modules/@common/user/redux/selectors';

import { FormRow, FormRowItem, useFormSettings } from '@/modules/@common/Form';
import { Autocomplete, Button, Paper, Switch, TextField } from '@/mui/components';

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

function GeneralTab() {
  const { size } = useFormSettings();
  const dispatch = useDispatch();
  const router = useRouter();

  // selectors
  const firstName = useSelector(selectors.firstNameSelector);
  const lastName = useSelector(selectors.lastNameSelector);
  const email = useSelector(selectors.emailSelector);
  const status = useSelector(selectors.statusSelector);
  const timezone = useSelector(selectors.timezoneSelector);
  const timezoneOptions = useSelector(selectors.timezoneOptionsSelector);
  const account = useSelector(selectors.accountSelector);
  const accountOptions = useSelector(selectors.accountOptionsSelector);
  const contentOwner = useSelector(selectors.contentOwnerSelector);
  const contentOwnersOptions = useSelector(selectors.contentOwnersOptionsSelector);
  const role = useSelector(selectors.roleSelector);
  const roleOptions = useSelector(selectors.roleOptionsSelector);
  const enable2fa = useSelector(selectors.enable2faSelector);
  const scheme = useSelector(selectors.schemeSelector);
  const publisherIds = useSelector(selectors.publisherIdsSelector);
  const defaultHub = useSelector(selectors.defaultHubSelector);
  const allSites = useSelector(selectors.allSitesSelector);
  const sendInvite = useSelector(selectors.sendInviteSelector);
  const department = useSelector(selectors.departmentSelector);
  const departmentOptions = useSelector(selectors.departmentOptionsSelector);
  const updateDate = useSelector(selectors.updateDateSelector);
  const updatedBy = useSelector(selectors.updatedBySelector);

  const userPermissions = useSelector(getUserPermissionsSelector);
  const hasAccount = useSelector(getUserRoleTypeSelector) === ACCOUNT;
  const userTimezone = useSelector(getUserTimezoneSelector);
  const userAccount = useSelector(getUserAccountSelector);
  const userAccountId = useSelector(getUserAccountIdSelector);
  const userPublisherIds = useSelector(getPublisherIdsSelector);

  const autocompleteRoleOptions = useMemo(() => {
    const roles$ = hasAccount
      ? (roleOptions?.filter(({ readOnlyInSelfServe }) => !readOnlyInSelfServe) ?? [])
      : (roleOptions ?? []);

    return roles$.filter(({ type }) => type !== EXTERNAL);
  }, [hasAccount, roleOptions]);

  const id = parseInt(router.query.id, 10);
  const canReadOnly = getCanReadOnly(id, userPermissions);

  const [departmentQuery, setDepartmentQuery] = useState('');

  // handlers
  const handleSetState = (state) => {
    if (Object.prototype.hasOwnProperty.call(state, 'role')) {
      if (state.role.type === INTERNAL && state.role.name === 'admin') {
        state.enable2fa = true;
      }
    }

    return dispatch(setAction(state));
  };

  const timezoneValue = useMemo(() => {
    const res = timezoneOptions?.find((zone) => zone.value === timezone);
    if (res) {
      return {
        label: res.label,
        value: res.value,
      };
    }

    return timezone;
  }, [timezone]);

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

  useEffect(() => {
    if (hasAccount && !account) {
      handleSetState({
        account: deepClone({
          id: +userAccountId,
          ...userAccount,
        }),
      });
    }
  });

  useEffect(() => {
    if (!timezone && timezoneOptions) {
      handleSetState({
        timezone: userTimezone,
      });
    }
  }, [timezone, timezoneOptions, userTimezone]);

  const hubs = useMemo(() => {
    if (allSites) {
      return [{ ...OPTION_ALL }];
    }
    if (account?.publishers) {
      return (publisherIds || []).map((id$) => {
        const res = account.publishers.find((p) => p.id === id$);

        return {
          name: res.name,
          id: res.id,
        };
      });
    }

    return [];
  }, [account?.publishers, publisherIds, allSites]);

  const publisherOptions = useMemo(() => {
    if (!userPublisherIds) {
      return role?.name === HUB_ADMIN_ROLE
        ? account?.publishers || []
        : [{ ...OPTION_ALL }, ...(account?.publishers || [])];
    }
    const accountPublishers = account?.publishers.filter((p) => userPublisherIds.includes(p.id)) || [];
    const allIncluded = account?.publishers.length === accountPublishers.length;

    return allIncluded && role?.name !== HUB_ADMIN_ROLE
      ? [{ ...OPTION_ALL }, ...(accountPublishers || [])]
      : accountPublishers;
  }, [account?.publishers, role]);

  const defaultPublisherValue = useMemo(() => {
    if (defaultHub === null || defaultHub === undefined) {
      return null;
    }

    const option = publisherOptions.find((p) => p.id === defaultHub);

    return {
      name: option?.name ?? defaultHub,
      id: defaultHub,
    };
  }, [defaultHub, publisherOptions]);

  return (
    <>
      <FormRow label="First Name">
        <TextField
          size={size}
          placeholder="Enter First Name"
          value={firstName}
          disabled={canReadOnly}
          onChange={(e) => handleSetState({ firstName: e.target.value })}
          {...getInputPropsByName(scheme, ['firstName'])}
          onFocus={() => dispatch(removeErrorByPropAction(['firstName']))}
        />
      </FormRow>
      <FormRow label="Last Name">
        <TextField
          size={size}
          placeholder="Enter Last Name"
          value={lastName}
          disabled={canReadOnly}
          onChange={(e) => handleSetState({ lastName: e.target.value })}
          {...getInputPropsByName(scheme, ['lastName'])}
          onFocus={() => dispatch(removeErrorByPropAction(['lastName']))}
        />
      </FormRow>
      <FormRow label="Email">
        <TextField
          size={size}
          placeholder="Enter Email"
          value={email}
          disabled={canReadOnly || !!id}
          onChange={(e) => handleSetState({ email: e.target.value })}
          {...getInputPropsByName(scheme, ['email'])}
          onFocus={() => dispatch(removeErrorByPropAction(['email']))}
        />
      </FormRow>
      <FormRow label="Time Zone">
        <Autocomplete
          value={timezoneValue}
          options={timezoneOptions || []}
          loading={!timezoneOptions}
          size={size}
          disableClearable
          onOpen={() => dispatch(getTimezoneOptionsAction())}
          onChange={(e, selected) =>
            handleSetState({
              timezone: selected?.value || selected,
            })
          }
          renderInput={(params) => (
            <TextField
              {...params}
              value=""
              placeholder="Time Zone"
              {...getInputPropsByName(scheme, ['timezone'])}
              onFocus={() => dispatch(removeErrorByPropAction(['timezone']))}
            />
          )}
        />
      </FormRow>
      <FormRow label="Role">
        <Autocomplete
          value={role}
          options={autocompleteRoleOptions}
          loading={!autocompleteRoleOptions}
          size={size}
          disableClearable
          disabled={id && role && role.type === EXTERNAL}
          onOpen={() => dispatch(getRoleOptionsAction())}
          onChange={(e, selected) => {
            const updateObj = {
              role: selected,
            };

            if (role && role.name !== selected.name) {
              if (!hasAccount) {
                updateObj.account = null;
              }

              updateObj.enable2fa = role?.name === 'admin';
              updateObj.defaultHub = null;
              updateObj.department = null;
              updateObj.publisherIds = [];
              updateObj.allSites = 0;
              updateObj.contentOwner = null;
            }

            return handleSetState(updateObj);
          }}
          renderInput={(params) => (
            <TextField
              {...params}
              value=""
              placeholder="Role"
              {...getInputPropsByName(scheme, ['role'])}
              onFocus={() => dispatch(removeErrorByPropAction(['role']))}
            />
          )}
        />
      </FormRow>
      {role && ![INTERNAL, EXTERNAL].includes(role.type) && (
        <>
          {role.type === API ? (
            <FormRow label="Content Owner">
              <Autocomplete
                value={contentOwner}
                options={contentOwnersOptions || []}
                loading={!contentOwnersOptions}
                size={size}
                filterSelectedOptions
                disableClearable
                onChange={(e, selected) => {
                  handleSetState({
                    contentOwner: selected,
                  });
                }}
                onOpen={() => {
                  dispatch(getContentOwnersOptionsAction(''));
                }}
                onInputChange={(e, searchText) => dispatch(getContentOwnersOptionsAction(searchText))}
                renderInput={(params) => (
                  <TextField
                    {...params}
                    value=""
                    placeholder="Select Content Owner"
                    {...getInputPropsByName(scheme, ['contentOwner'])}
                    onFocus={() => dispatch(removeErrorByPropAction(['contentOwner']))}
                  />
                )}
              />
            </FormRow>
          ) : (
            <>
              {!hasAccount && (
                <FormRow label="Account">
                  <Autocomplete
                    value={account}
                    options={accountOptions || []}
                    loading={!accountOptions}
                    size={size}
                    filterSelectedOptions
                    disableClearable
                    onChange={(e, selected) => {
                      handleSetState({
                        account: selected,
                        defaultHub: null,
                        department: null,
                        publisherIds: [],
                      });
                    }}
                    onOpen={() => {
                      dispatch(getAccountOptionsAction(''));
                    }}
                    onInputChange={(e, searchText) => dispatch(getAccountOptionsAction(searchText))}
                    renderInput={(params) => (
                      <TextField
                        {...params}
                        value=""
                        placeholder="Select Account"
                        {...getInputPropsByName(scheme, ['account'])}
                        onFocus={() => dispatch(removeErrorByPropAction(['account']))}
                      />
                    )}
                  />
                </FormRow>
              )}
              {!!account && (
                <>
                  <FormRow label="Hubs">
                    <Autocomplete
                      value={hubs}
                      limitTags={10}
                      options={publisherOptions}
                      loading={!publisherOptions}
                      size={size}
                      multiple
                      filterSelectedOptions
                      disableCloseOnSelect
                      optionLabelKey="name"
                      optionValueKey="id"
                      onChange={(e, publisherIds$, reason, single) => {
                        if (!publisherIds$.length) {
                          handleSetState({
                            publisherIds: [],
                            defaultHub: null,
                            allSites: 0,
                          });
                        } else if (single?.option.id === OPTION_ALL_ID) {
                          handleSetState({
                            publisherIds: [],
                            allSites: 1,
                          });
                        } else {
                          const selectedHubIds = publisherIds$
                            .filter((item) => item.id !== OPTION_ALL_ID)
                            .map((item) => item.id);

                          handleSetState({
                            allSites: 0,
                            publisherIds: selectedHubIds,
                            ...(defaultHub && !selectedHubIds.includes(defaultHub) ? { defaultHub: null } : {}),
                          });
                        }
                      }}
                      renderInput={(params) => (
                        <TextField
                          {...params}
                          placeholder="Select Hubs"
                          {...getInputPropsByName(scheme, ['publisherIds'])}
                          onFocus={() => dispatch(removeErrorByPropAction(['publisherIds']))}
                        />
                      )}
                    />
                  </FormRow>
                  {!!hubs.length && (
                    <FormRow label="Default Hub">
                      <Autocomplete
                        value={defaultPublisherValue}
                        options={
                          !allSites
                            ? (hubs || []).filter((item) => item.id !== OPTION_ALL_ID)
                            : account?.publishers || []
                        }
                        size={size}
                        optionLabelKey="name"
                        optionValueKey="id"
                        onChange={(e, selected) =>
                          handleSetState({
                            defaultHub: selected ? selected.id : null,
                          })
                        }
                        renderInput={(params) => <TextField {...params} placeholder="Select Default Hub" />}
                      />
                    </FormRow>
                  )}
                  <FormRow label="Department">
                    <Autocomplete
                      value={department}
                      options={departmentOptions || []}
                      size={size}
                      inputValue={departmentQuery}
                      optionLabelKey="name"
                      optionValueKey="id"
                      onOpen={() => dispatch(getDepartmentOptionsAction(''))}
                      onInputChange={(e, searchText) => {
                        setDepartmentQuery(searchText);

                        dispatch(getDepartmentOptionsAction(searchText));
                      }}
                      onChange={(e, selected) => handleSetState({ department: selected })}
                      renderInput={(params) => <TextField {...params} placeholder="Select Department" />}
                      PaperComponent={({ children }) => (
                        <Paper className={styles.DepartmentPaper}>
                          {!!departmentQuery &&
                            departmentOptions &&
                            !departmentOptions?.some((d) => d.name === departmentQuery) && (
                              <div className={styles.DepartmentButtonWrapper}>
                                <Button
                                  size="small"
                                  color="primary"
                                  variant="contained"
                                  fullWidth
                                  multiline
                                  onMouseDown={() => {
                                    dispatch(createDepartmentAction(departmentQuery));
                                  }}
                                >
                                  {`Add department: ${departmentQuery}`}
                                </Button>
                              </div>
                            )}
                          {children}
                        </Paper>
                      )}
                    />
                  </FormRow>
                </>
              )}
            </>
          )}
        </>
      )}

      <FormRow label="Enable 2FA" tooltip="Multi Factor Authentication">
        <Switch
          color="primary"
          size={size}
          checked={enable2fa}
          disabled={canReadOnly || (role?.type === INTERNAL && role?.name === 'admin')}
          onChange={(e) =>
            handleSetState({
              enable2fa: e.target.checked,
            })
          }
        />
      </FormRow>
      {!!id && (
        <FormRow label="Enabled">
          <Switch
            color="primary"
            size={size}
            checked={status === STATUSES_ACTIVE}
            disabled={canReadOnly}
            onChange={(e) =>
              handleSetState({
                status: e.target.checked ? STATUSES_ACTIVE : STATUSES_INACTIVE,
              })
            }
          />
        </FormRow>
      )}
      {!id && (
        <FormRow label="Send Invite">
          <Switch
            color="primary"
            size={size}
            checked={sendInvite}
            disabled={canReadOnly}
            onChange={(e) =>
              handleSetState({
                sendInvite: !!e.target.checked,
              })
            }
          />
        </FormRow>
      )}
      {updateDate && (
        <FormRow label="Updated Date">
          <FormRowItem itemsInRow={1}>{dayjs(updateDate).format('MMM D, YYYY hh:mm A')}</FormRowItem>
        </FormRow>
      )}
      {updatedBy && (
        <FormRow label="Updated By">
          <FormRowItem itemsInRow={1}>{updatedBy}</FormRowItem>
        </FormRow>
      )}
    </>
  );
}

export default GeneralTab;
