import { ReactNode, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation } from 'react-query';
import { useNavigate } from 'react-router';

import { useModal } from '@material-hu/hooks/useModal';
import { IconList, IconSettings, TablerIcon } from '@material-hu/icons/tabler';

import Button from '@material-hu/components/design-system/Buttons/Button';
import Dialog from '@material-hu/components/design-system/Dialog';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import useAuth from 'src/contexts/JWTContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import useRequiredParams from 'src/hooks/useRequiredParams';
import { getGroupDetails, editGroup } from 'src/services/groupsService';
import { CriteriaType } from 'src/types/audience';
import {
  EditGroupBody,
  Group,
  GroupPrivacyPolicies,
  GroupApprovalPolicies,
  GroupPublicationPolicies,
} from 'src/types/groups';
import { IconInterface } from 'src/types/icons';
import { removeURLParams, signedUpload } from 'src/utils/filesUtils';
import { formatTitle } from 'src/utils/helmetUtils';
import { formatDefaultIcon, formatOutgoingIcon } from 'src/utils/icons';
import { logEvent, LogEvents } from 'src/utils/logging';

import GroupManagementLayout from '../components/GroupManagementLayout';
import ManageConfiguration from '../components/ManageConfiguration';
import MembersList from '../components/MembersList';
import { ConfigurationTool } from '../constants';
import { groupsKeys } from '../queries';
import { groupRoutes } from '../routes';
import { memberIsFromGroupCreatorInstance } from '../utils';

const { CONFIGURATION, MANAGE_MEMBERS } = ConfigurationTool;

type Step = {
  id: ConfigurationTool;
  label: string;
  icon: TablerIcon;
  Component: React.ComponentType<{
    disabled?: boolean;
  }>;
  disabled?: boolean;
};

const EditGroup = () => {
  const [activeStep, setActiveStep] =
    useState<ConfigurationTool>(CONFIGURATION);

  const { t } = useTranslation(['group']);
  const navigate = useNavigate();
  const HuGoThemeProvider = useHuGoTheme();
  const { enqueueSnackbar } = useHuSnackbar();
  const showGeneralError = useGeneralError();
  const { user, instance } = useAuth();
  const { id: groupId } = useRequiredParams(['id']);

  const form = useForm<{
    title: string;
    description: string;
    banner?: { url: string; file: File | null };
    icon: IconInterface;
    privacyPolicy: GroupPrivacyPolicies;
    approvalPolicy: GroupApprovalPolicies;
    membersPolicy: CriteriaType;
    publicationPolicy: GroupPublicationPolicies;
    isMultiCompany: boolean;
    membersCanLeave: string;
  }>({
    defaultValues: {
      title: '',
      description: '',
      banner: undefined,
      icon: formatDefaultIcon(),
      privacyPolicy: GroupPrivacyPolicies.OPEN,
      approvalPolicy: GroupApprovalPolicies.NOT_NEEDED,
      membersPolicy: CriteriaType.ALL_USERS,
      publicationPolicy: GroupPublicationPolicies.OPEN,
      isMultiCompany: false,
      membersCanLeave: 'false',
    },
    mode: 'onChange',
  });

  const {
    data: groupData,
    isLoading,
    isFetching,
  } = useQuery(
    groupsKeys.groupDetails(groupId!),
    () => getGroupDetails(groupId!),
    {
      onSuccess: (response: Group) => {
        form.reset({
          title: response?.title || '',
          banner: response?.bannerUrl
            ? { url: response?.bannerUrl, file: null }
            : undefined,
          description: response?.description || '',
          icon: formatDefaultIcon(response?.icon),
          privacyPolicy: response?.privacyPolicy,
          approvalPolicy: response?.approvalPolicy,
          membersPolicy: CriteriaType.ALL_USERS,
          publicationPolicy: response?.publicationPolicy,
          isMultiCompany: response?.isMultiCompany ?? false,
          membersCanLeave: response?.membersCanLeave ? 'true' : 'false',
        });
      },
      select: r => r.data,
      enabled: !!groupId,
    },
  );

  const isMultiCompany = groupData?.isMultiCompany ?? false;
  const isFromCreatorInstance = memberIsFromGroupCreatorInstance(
    instance?.id,
    groupData?.instanceId,
  );

  // For multicompany groups, non-creators can only view (disabled) the config tab
  const isConfigDisabled = isMultiCompany && !isFromCreatorInstance;

  const {
    watch,
    formState: { isDirty },
  } = form;

  const { title, icon } = watch();

  const steps: Step[] = [
    {
      id: CONFIGURATION,
      label: t('group:configure'),
      icon: IconSettings,
      Component: ManageConfiguration,
      disabled: false,
    },
    {
      id: MANAGE_MEMBERS,
      label: t('group:members'),
      icon: IconList,
      Component: MembersList,
      disabled: isDirty,
    },
  ];

  const { mutate: editGroupMutation, isLoading: isEditing } = useMutation(
    async ({ banner, ...body }: EditGroupBody) => {
      let bannerUrl = banner?.url ? removeURLParams(banner?.url) : null;

      if (banner?.file) {
        const signedURL = await signedUpload(banner.file);
        bannerUrl = removeURLParams(signedURL);
      }
      return editGroup(groupId!, { ...body, bannerUrl });
    },
    {
      onSuccess: ({ data: newState }) => {
        enqueueSnackbar({ title: t('group:success'), variant: 'success' });
        logEvent(LogEvents.GROUPS_GROUP_UPDATED, {
          userId: user?.id,
          groupId,
          newState,
        });
        navigate(groupRoutes.base());
      },
      onError: err => showGeneralError(err),
    },
  );

  const { showModal, modal, closeModal } = useModal(() => (
    <Dialog
      title={t('group:close_without_saving')}
      textBody={t('group:close_without_saving_info')}
      primaryButtonProps={{
        children: t('group:accept_close'),
        onClick: () => navigate(groupRoutes.base()),
      }}
      secondaryButtonProps={{
        children: t('group:cancel'),
        onClick: closeModal,
      }}
      onClose={closeModal}
    />
  ));

  const isLoadingGroup = isLoading || isFetching;

  const goBack = () => (isDirty ? showModal() : navigate(groupRoutes.base()));

  const handleSave = () => {
    const formValues = form.getValues();
    const body = {
      ...formValues,
      description: formValues?.description || undefined,
      icon: formatOutgoingIcon(formValues?.icon),
      banner: formValues?.banner,
      membersCanLeave: formValues?.membersCanLeave === 'true',
    };

    editGroupMutation(body);
  };

  const activeConfiguration = steps.find(step => step.id === activeStep);
  const activeConfigurationProps = {
    disabled: activeStep === CONFIGURATION ? isConfigDisabled : undefined,
  };

  const isManageMembers = activeStep === MANAGE_MEMBERS;

  let footerActions: ReactNode = null;
  if (!isManageMembers) {
    footerActions = (
      <>
        <Button
          variant="tertiary"
          size="large"
          onClick={goBack}
        >
          {t('general:cancel')}
        </Button>
        <Button
          variant="primary"
          size="large"
          id="continue-stepper-button"
          onClick={handleSave}
          disabled={isEditing || !title.length || !isDirty}
        >
          {t('group:finish')}
        </Button>
      </>
    );
  }

  return (
    <HuGoThemeProvider>
      <Helmet>
        <title>
          {formatTitle(t('group:group_configuration', { name: title }))}
        </title>
      </Helmet>
      {modal}
      <FormProvider {...form}>
        <GroupManagementLayout
          title={title}
          icon={icon}
          steps={steps}
          activeComponent={
            activeConfiguration ? (
              <activeConfiguration.Component {...activeConfigurationProps} />
            ) : null
          }
          footerActions={footerActions}
          onClose={goBack}
          activeStep={activeStep}
          onStepSelect={step => setActiveStep(step as ConfigurationTool)}
          isLoading={isLoadingGroup}
        />
      </FormProvider>
    </HuGoThemeProvider>
  );
};

export default EditGroup;
