import { type FC, type ReactNode, useEffect } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation, useQuery } from 'react-query';
import { useNavigate, useSearchParams } from 'react-router-dom';

import { useModal } from '@material-hu/hooks/useModal';
import { IconList, IconSettings } 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 useSnackbar from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/logging';
import { DEFAULT_IMAGE_ICON_URL } from 'src/constants/env';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { signedUpload } from 'src/pages/dashboard/serviceManagement/utils';
import { addMembers, createGroup, getGroupDetails } from 'src/services/groups';
import { EventName } from 'src/types/amplitude';
import {
  GroupApprovalPolicies,
  type GroupBody,
  GroupPrivacyPolicies,
  GroupPublicationPolicies,
  type GroupStep,
  GroupsStepsType,
} from 'src/types/groups';
import { IconTypes } from 'src/types/icons';
import { type User } from 'src/types/user';
import { preprocessImage, revokeLocalUrl } from 'src/utils/files';
import { userIsOnManageGroupPage } from 'src/utils/groups';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation as useTranslation } from 'src/utils/i18n';
import { formatOutgoingIcon } from 'src/utils/icons';

import GroupManagementLayout from '../components/GroupManagementLayout';
import { useGroupSteps } from '../hooks/useGroupSteps';
import {
  groupsKeys,
  groupsMutationKeys,
  invalidateGroup,
  invalidateGroupDetails,
} from '../queries';
import { groupsRoutes } from '../routes';

import ManageConfiguration from './components/ManageConfiguration';
import ManageMembers from './components/ManageMembers';

const { GENERAL_ASPECTS, MANAGE_MEMBERS } = GroupsStepsType;

const CreateGroup: FC = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const groupId = searchParams.get('groupId');

  const { user } = useAuth();
  const userId = user?.id;
  const navigate = useNavigate();
  const { t } = useTranslation(['post']);
  const showGeneralError = useGeneralError();
  const { enqueueSnackbar } = useSnackbar();

  const { activeStep, setActiveStep, getActiveConfiguration } = useGroupSteps({
    initialStep: groupId ? MANAGE_MEMBERS : GENERAL_ASPECTS,
  });

  const form = useForm<{
    title: string;
    description: string;
    banner: any;
    icon: {
      type: IconTypes;
      value: string;
      file: any;
    };
    privacyPolicy: GroupPrivacyPolicies;
    approvalPolicy: GroupApprovalPolicies;
    publicationPolicy: GroupPublicationPolicies;
    members: User[];
    isMultiCompany: boolean;
    membersCanLeave: boolean;
  }>({
    defaultValues: {
      title: '',
      description: '',
      banner: undefined,
      icon: {
        type: IconTypes.IMAGE,
        value: DEFAULT_IMAGE_ICON_URL,
        file: undefined,
      },
      privacyPolicy: GroupPrivacyPolicies.OPEN,
      approvalPolicy: GroupApprovalPolicies.NOT_NEEDED,
      publicationPolicy: GroupPublicationPolicies.OPEN,
      members: [],
      isMultiCompany: false,
      membersCanLeave: false,
    },
    mode: 'onChange',
  });
  const { title, members } = form.watch();
  const socket = useSocket();

  const {
    modal: assignMembersModal,
    showModal: showAssignMembersModal,
    closeModal: closeAssignMembersModal,
  } = useModal(
    () => (
      <Dialog
        title={t('group:group_created')}
        textBody={t('group:select_collaborators')}
        primaryButtonProps={{
          children: t('group:assign_members'),
          onClick: () => {
            setActiveStep(MANAGE_MEMBERS);
            closeAssignMembersModal();
          },
        }}
        secondaryButtonProps={{
          children: t('general:later'),
          onClick: () => {
            closeAssignMembersModal();
            if (groupId) {
              navigate(groupsRoutes.detail(groupId));
            }
          },
        }}
        onClose={closeAssignMembersModal}
      />
    ),
    { maxWidth: 'xs' },
  );

  const { mutate: createNewGroup, isLoading: isCreatingGroup } = useMutation(
    async ({ banner, ...body }: GroupBody) => {
      let bannerUrl: string | undefined;
      if (banner) {
        bannerUrl = await preprocessImage(banner);
      }
      const createGroupBody = { ...body, bannerUrl };

      if (createGroupBody.icon.file) {
        // Replace blob url with uploaded s3 url
        revokeLocalUrl(createGroupBody.icon.value);
        const logoUrl = await uploadLogo.mutateAsync(createGroupBody.icon.file);
        createGroupBody.icon = { value: logoUrl, type: IconTypes.IMAGE };
      }

      createGroupBody.icon = formatOutgoingIcon(createGroupBody.icon);
      return createGroup(createGroupBody);
    },
    {
      mutationKey: groupsMutationKeys.create(),
      onSuccess: ({ data }) => {
        enqueueSnackbar({
          title: t('group:create_success'),
          variant: 'success',
        });
        logEvent(EventName.GROUPS_GROUP_CREATED, {
          userId,
          groupId: data.id,
        });
        form.reset({
          title: data.title,
          description: data.description || '',
          banner: undefined,
          icon: {
            type: data.icon.type,
            value: data.icon.value,
            file: undefined,
          },
          privacyPolicy: data.privacyPolicy,
          approvalPolicy: data.approvalPolicy,
          publicationPolicy: data.publicationPolicy,
          members: data.members || [],
        });
        setSearchParams({ groupId: data.id.toString() });
        showAssignMembersModal();
      },
      onError: err => showGeneralError(err),
    },
  );

  const { mutate: addMembersMutation, isLoading: isEditing } = useMutation(
    (userIds: number[]) => {
      if (!groupId) {
        throw new Error('Group ID is required');
      }
      return addMembers(groupId, userIds);
    },
    {
      onSuccess: () => {
        enqueueSnackbar({
          title: t('group:invite_sent'),
          variant: 'success',
        });
        if (groupId) {
          invalidateGroup(Number(groupId));
          navigate(groupsRoutes.detail(groupId));
        }
      },
    },
  );

  const { isLoading: isLoadingGroup } = useQuery(
    groupsKeys.detail(groupId!),
    () => getGroupDetails(groupId!),
    {
      onSuccess: ({ data }) => {
        form.reset({
          ...form.getValues(),
          title: data.title,
          icon: {
            type: data.icon.type,
            value: data.icon.value,
            file: undefined,
          },
        });
      },
      onError: err => {
        showGeneralError(err, t('error_loading_group'));
      },
      enabled: !!groupId && !title,
    },
  );

  const uploadLogo = useMutation((file: File) => signedUpload(file, true), {
    onError: err => showGeneralError(err),
  });

  const handleCreate = () => {
    const { description, ...formValues } = form.getValues();

    createNewGroup({
      ...formValues,
      description: description || undefined,
    });
  };

  const handleSave = () => {
    const { members: groupMembers } = form.getValues();
    const userIds = groupMembers.map(member => member.id);
    addMembersMutation(userIds);
  };

  useEffect(() => {
    const refetchGroupDetails = ({
      groupId: eventGroupId,
    }: {
      groupId: string;
    }) => {
      const isOnUpdatedGroup = userIsOnManageGroupPage(eventGroupId);
      if (isOnUpdatedGroup) {
        invalidateGroupDetails(Number(eventGroupId));
      }
    };

    socket.listenEvent(
      EVENTS_SOCKETS.GROUP_HAS_PENDING_REQUESTS_UPDATED,
      refetchGroupDetails,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.GROUP_HAS_PENDING_REQUESTS_UPDATED,
        refetchGroupDetails,
      );
    };
  }, [socket]);

  const steps: GroupStep[] = [
    {
      id: GENERAL_ASPECTS,
      label: t('group:configure'),
      icon: IconSettings,
      Component: ManageConfiguration,
      disabled: activeStep !== GENERAL_ASPECTS,
    },
    {
      id: MANAGE_MEMBERS,
      label: t('group:members'),
      icon: IconList,
      Component: ManageMembers,
      disabled: activeStep !== MANAGE_MEMBERS,
    },
  ];

  const activeConfiguration = getActiveConfiguration(steps);

  let footerActions: ReactNode = null;
  if (activeStep === GENERAL_ASPECTS) {
    footerActions = (
      <>
        <Button
          variant="tertiary"
          size="large"
          onClick={() => navigate(-1)}
        >
          {t('general:cancel')}
        </Button>
        <Button
          variant="primary"
          size="large"
          onClick={handleCreate}
          disabled={!title}
          loading={isCreatingGroup}
        >
          {t('group:group_creation')}
        </Button>
      </>
    );
  }
  if (activeStep === MANAGE_MEMBERS) {
    footerActions = (
      <>
        <Button
          variant="tertiary"
          size="large"
          onClick={() => navigate(-1)}
        >
          {t('general:cancel')}
        </Button>
        <Button
          variant="primary"
          size="large"
          disabled={
            members?.length === 0 ||
            form.formState.isSubmitting ||
            isEditing ||
            uploadLogo.isLoading ||
            isLoadingGroup
          }
          onClick={handleSave}
        >
          {t('general:save')}
        </Button>
      </>
    );
  }

  return (
    <>
      <Helmet>
        <title>{formatTitle(t('group:group_creation'))}</title>
      </Helmet>
      <FormProvider {...form}>
        <GroupManagementLayout
          title={t('group:create_group')}
          steps={steps}
          activeComponent={
            activeConfiguration ? <activeConfiguration.Component /> : null
          }
          footerActions={footerActions}
          onClose={() => navigate(groupsRoutes.groups())}
          activeStep={activeStep}
          onStepSelect={setActiveStep}
          isLoading={isLoadingGroup}
        />
      </FormProvider>
      {assignMembersModal}
    </>
  );
};

const CreateGroupWithHuGoTheme: FC = () => {
  const HugoThemeProvider = useHuGoTheme();

  return (
    <HugoThemeProvider>
      <CreateGroup />
    </HugoThemeProvider>
  );
};

export default CreateGroupWithHuGoTheme;
