import { FormProvider, useForm } from 'react-hook-form';
import { useMutation, useQuery } from 'react-query';

import { isEmpty, omit, size } from 'lodash-es';
import Stack from '@material-hu/mui/Stack';

import Alert from '@material-hu/components/design-system/Alert';
import CardContainer from '@material-hu/components/design-system/CardContainer';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import { useDrawerLayerItem } from '@material-hu/components/layers/Drawers';

import { logEvent } from 'src/config/logging';
import { queryClient } from 'src/config/react-query';
import { useRequiredAuth } from 'src/contexts/JWTContext';
import { profileKeys } from 'src/pages/dashboard/profile/queries';
import {
  dynamicFieldsResponse,
  patchUser,
  patchUserProfileData,
} from 'src/services/users';
import { EventName } from 'src/types/amplitude';
import { type ProfileDataMap } from 'src/types/instance';
import { type User, type UserProfile } from 'src/types/user';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getDirtyValues } from 'src/utils/profile';

import {
  filterProfileData,
  formatProfileDataBeforeSubmit,
  formatProfileDataForForm,
  getInputs,
} from '../utils';

import useFieldComponents from './useFieldComponent';

export const useEditProfileDrawer = (user: UserProfile) => {
  const { instance } = useRequiredAuth();

  const { t } = useLokaliseTranslation('profile');
  const { enqueueSnackbar } = useSnackbar();

  const { data: profileFields } = useQuery({
    queryKey: profileKeys.profileFields(instance.id),
    queryFn: () => dynamicFieldsResponse(instance.id),
    select: r => filterProfileData(r.data),
  });

  const resolvedProfileFields: ProfileDataMap = profileFields ?? {};

  const fields = getInputs(instance, t, resolvedProfileFields);

  const form = useForm({
    values: {
      profileData: formatProfileDataForForm(resolvedProfileFields, user),
      firstName: user.firstName,
      lastName: user.lastName,
      nickname: user.nickname || '',
      birthdate: user.birthdate ? new Date(user.birthdate) : null,
      phoneNumber: user.phoneNumber || '',
      email: user.email || '',
      allowWhatsApp: user.socialNetworks?.allowWhatsApp || false,
      linkedIn: user.socialNetworks?.linkedIn || '',
      instagram: user.socialNetworks?.instagram || '',
      facebook: user.socialNetworks?.facebook || '',
      twitter: user.socialNetworks?.twitter || '',
    },
  });

  const mutation = useMutation(
    async (values: Record<string, unknown>) => {
      const { profileData, ...basicInfo } = values;

      if (!isEmpty(basicInfo)) {
        await patchUser(user.id, basicInfo as Partial<User>);
        logEvent(EventName.USER_PROFILE_UPDATE);
      }

      if (!isEmpty(profileData)) {
        await patchUserProfileData(user.id, profileData as object);
        logEvent(EventName.USER_PROFILE_FIELDS_UPDATE);
      }
    },
    {
      onSuccess: async () => {
        await queryClient.invalidateQueries(profileKeys.detail(user.id));
        closeDrawer();
        enqueueSnackbar({ title: t('profile_updated'), variant: 'success' });
      },
      onError: () => {
        enqueueSnackbar({ title: t('error_edit'), variant: 'error' });
      },
    },
  );

  const submit = form.handleSubmit((newData: object) => {
    const dirtyFields = getDirtyValues(form.formState.dirtyFields, newData);
    const dirtyValues = formatProfileDataBeforeSubmit(
      dirtyFields,
      resolvedProfileFields,
    );
    mutation.mutate(dirtyValues);
  });

  const close = () => {
    form.reset();
    closeDrawer();
  };

  const { renderField } = useFieldComponents();

  const { errors, dirtyFields } = form.formState;
  const errorsCount =
    size(omit(errors, 'profileData')) + size(errors?.profileData ?? {});
  const hasErrors = errorsCount > 0;
  const hasDirtyFields = size(dirtyFields) > 0;

  const { openDrawer: openEditProfile, closeDrawer } = useDrawerLayerItem(
    'edit_profile',
    {
      onClose: () => close(),
      title: t('edit_profile'),
      primaryButtonProps: {
        children: t('general:save'),
        onClick: submit,
        loading: mutation.isLoading,
        disabled: hasErrors || !hasDirtyFields,
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => close(),
      },
      children: (
        <FormProvider {...form}>
          <Stack sx={{ gap: 2 }}>
            {fields.map(field => (
              <CardContainer
                fullWidth
                key={field.name}
                sx={{
                  backgroundColor: ({ palette }) =>
                    palette.new.background.elements.grey,
                }}
              >
                {renderField(field)}
              </CardContainer>
            ))}
          </Stack>
        </FormProvider>
      ),
      footer: hasErrors && (
        <Alert
          title={t('fields_with_errors', { count: errorsCount })}
          severity="error"
        />
      ),
    },
  );

  return { openEditProfile };
};
