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

import { type GetDrawerConfiguration } from '@material-hu/hooks/useDrawerV2';

import HuCircularProgress from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import { logEvent } from 'src/config/logging';
import { invalidateTimeOffNotifications } from 'src/hooks/queryHooks/vacations';
import useFormatDate from 'src/hooks/useFormatDate';
import useGeneralError from 'src/hooks/useGeneralError';
import {
  editVacationRequest as editVacationRequestService,
  getRequestedEditDaysPreview,
} from 'src/services/vacations';
import { EventName } from 'src/types/amplitude';
import {
  type RequestTimeOff,
  type ResponseRequestTimeOff,
} from 'src/types/vacations';
import { useLokaliseTranslation } from 'src/utils/i18n';
import {
  areDatesValid,
  formatDateRequest,
  formatEditRequest,
} from 'src/utils/vacations';

import { formFieldsRequestCreate } from '../../constant';
import {
  assignEditionValues,
  HoursRequestType,
  type RequestCreateForm,
} from '../../hooks/useRequestCreate';
import {
  updateRequestsManager,
  updateVacations,
  vacationsKeys,
} from '../../queries';
import { RequestForm } from '../requests/RequestForm';

import { CreateRequestFooter } from './footers/CreateRequestFooter';

export type EditRequestDrawerProps = {
  vacationDetail: ResponseRequestTimeOff;
};

const useEditRequestDrawer: GetDrawerConfiguration<EditRequestDrawerProps> = ({
  vacationDetail,
  closeDrawer,
}) => {
  const { t } = useLokaliseTranslation('time_off');
  const { formatDate } = useFormatDate();
  const { enqueueSnackbar } = useHuSnackbar();
  const showGeneralError = useGeneralError();

  const form = useForm<RequestCreateForm>({
    values: vacationDetail ? assignEditionValues(vacationDetail) : undefined,
    mode: 'onChange',
  });

  const [
    fromDate,
    consumptionTypeFrom,
    toDate,
    consumptionTypeTo,
    fromHour,
    fromHourTime,
    toHour,
    toHourTime,
    hoursRequestType,
    amountInMoney,
    amountInTime,
  ] = useWatch({
    control: form.control,
    name: [
      formFieldsRequestCreate.fromDate,
      formFieldsRequestCreate.consumptionTypeFromDate,
      formFieldsRequestCreate.toDate,
      formFieldsRequestCreate.consumptionTypeToDate,
      formFieldsRequestCreate.fromHour,
      formFieldsRequestCreate.fromHourTime,
      formFieldsRequestCreate.toHour,
      formFieldsRequestCreate.toHourTime,
      formFieldsRequestCreate.hoursRequestType,
      formFieldsRequestCreate.amountInMoney,
      formFieldsRequestCreate.amountInTime,
    ],
  });

  const formattedFromDate = useMemo(() => {
    if (!fromDate) return undefined;
    return formatDateRequest(
      {
        date: fromDate,
        consumptionType: consumptionTypeFrom,
        hourRequestType: hoursRequestType,
        hour: fromHour,
        minutes: fromHourTime,
      },
      formatDate,
    );
  }, [
    fromDate,
    consumptionTypeFrom,
    hoursRequestType,
    fromHour,
    fromHourTime,
    formatDate,
  ]);

  const formattedToDate = useMemo(() => {
    if (!toDate) return undefined;
    return formatDateRequest(
      {
        date:
          hoursRequestType === HoursRequestType.LESS_THAN_ONE_DAY
            ? fromDate
            : toDate,
        consumptionType: consumptionTypeTo,
        hourRequestType: hoursRequestType,
        hour: toHour,
        minutes: toHourTime,
      },
      formatDate,
    );
  }, [
    hoursRequestType,
    fromDate,
    toDate,
    consumptionTypeTo,
    formatDate,
    toHour,
    toHourTime,
  ]);

  const { data: requestedDays, isLoading: isLoadingRequestedDays } = useQuery(
    vacationsKeys.policyTypes.requestedDaysAmount(
      vacationDetail?.policyType.id!,
      vacationDetail?.issuer.id!,
      formattedFromDate,
      formattedToDate,
      amountInMoney?.value,
    ),
    () =>
      getRequestedEditDaysPreview(vacationDetail?.id, {
        policyTypeId: vacationDetail?.policyType.id,
        from: formattedFromDate,
        to: formattedToDate,
        amountInMoney: vacationDetail?.amountInMoney,
      }),
    {
      enabled: form.formState.isDirty && areDatesValid(fromDate, toDate),
      select: res => ({
        amount: res.data.amount,
        amountDiff: res.data.amountDiff,
        amountInMoney: res.data.amountInMoney || 0,
        amountInTime: res.data.amountInTime,
        warnings: res.data.warnings || {},
      }),
    },
  );

  const handleSuccess = () => {
    enqueueSnackbar({
      title: t('request_successfully_updated'),
      variant: 'success',
    });
    invalidateTimeOffNotifications();
    updateRequestsManager();
    updateVacations(vacationDetail?.id);
    logEvent(EventName.TIME_OFF_REQUEST_EDITED, {
      requestId: vacationDetail?.id,
      editor: 'admin',
      state: vacationDetail?.state,
    });
    closeDrawer();
  };

  const { mutate: editVacationRequest } = useMutation(
    (requestData: Partial<RequestTimeOff>) =>
      editVacationRequestService(vacationDetail?.id, requestData),
    {
      onSuccess: () => {
        handleSuccess();
      },
      onError: error => {
        showGeneralError(error);
      },
    },
  );

  const submit = (values: RequestCreateForm) => {
    const formattedData = formatEditRequest(values, formatDate);
    editVacationRequest(formattedData);
  };

  const handleSubmit = form.handleSubmit(submit);
  const disabledToSubmit = !form.formState.isDirty;

  const renderFooter = () => {
    if (isLoadingRequestedDays) return <HuCircularProgress centered />;

    if (!vacationDetail || !requestedDays) return null;

    const validDates = areDatesValid(fromDate, toDate);

    if (validDates) {
      return (
        <CreateRequestFooter
          policyType={vacationDetail.policyType}
          currentBalance={vacationDetail.policyType.amount}
          requestedDays={requestedDays.amount}
          amountDiff={requestedDays.amountDiff}
          amountInMoney={vacationDetail.amountInMoney}
          amountInTime={amountInTime}
          warningsRequestedDays={requestedDays.warnings}
          user={vacationDetail.issuer}
          isManagerRequesting={true}
        />
      );
    }

    return null;
  };

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

  return {
    title: t('edit_request'),
    children: (
      <FormProvider {...form}>
        <RequestForm
          amountInTime={amountInTime}
          user={vacationDetail?.issuer}
          isManagerRequesting={true}
          policyTypes={[vacationDetail?.policyType]}
          showingAllPolicies={false}
          policyType={vacationDetail?.policyType}
          customError={null}
          isEditing={true}
        />
      </FormProvider>
    ),
    footer: renderFooter(),
    primaryButtonProps: {
      children: t('save'),
      onClick: handleSubmit,
      disabled: disabledToSubmit,
    },
    secondaryButtonProps: {
      children: t('cancel'),
      onClick: handleCloseDrawer,
    },
    onClose: handleCloseDrawer,
  };
};

export default useEditRequestDrawer;
