import { useMemo } from 'react';
import { type UseFormReturn, useWatch } from 'react-hook-form';

import { isBefore, isEqual } from 'date-fns';

import { useGetRequestedDays } from 'src/hooks/queryHooks/vacations';
import useFormatDate from 'src/hooks/useFormatDate';
import { type MeUser } from 'src/types/user';
import { type PolicyTypes, UnitVacations } from 'src/types/vacations';
import { useLokaliseTranslation } from 'src/utils/i18n';
import {
  areDatesValid,
  formatValues,
  fromHourIsBeforeToHour,
  getErrorInAmountPerRequest,
  handleCustomErrors,
} from 'src/utils/vacations';

import { formFieldsRequestCreate } from '../constant';

import { HoursRequestType, type RequestCreateForm } from './useRequestCreate';

type UseRequestValidationsProps = {
  policyType: PolicyTypes | undefined;
  form: UseFormReturn<RequestCreateForm>;
  user: MeUser;
  openDrawer: boolean;
  isManagerRequesting: boolean;
};

export const useRequestValidations = ({
  policyType,
  form,
  user,
  openDrawer,
  isManagerRequesting,
}: UseRequestValidationsProps) => {
  const {
    formState: { isSubmitting, errors },
  } = form;
  const { t } = useLokaliseTranslation('time_off');
  const { formatDate } = useFormatDate();

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

  const formatedValues = useMemo(() => {
    return formatValues(
      {
        toDate,
        fromDate,
        consumptionTypeFromDate,
        consumptionTypeToDate,
        user,
        policyTypeId: policyTypeIdValue,
        issuerId: user?.id,
        fromHour,
        toHour,
        fromHourTime,
        toHourTime,
        hoursRequestType,
        amountInMoney,
        hasSellingBalance,
      },
      formatDate,
    );
  }, [
    toDate,
    fromDate,
    consumptionTypeFromDate,
    consumptionTypeToDate,
    user,
    policyTypeIdValue,
    fromHour,
    toHour,
    fromHourTime,
    toHourTime,
    hoursRequestType,
    amountInMoney,
    hasSellingBalance,
  ]);

  const validHourRequest = useMemo(() => {
    if (hoursRequestType === HoursRequestType.LESS_THAN_ONE_DAY) {
      if (
        !formatedValues.from?.time ||
        !formatedValues.to?.time ||
        !formatedValues.from?.date ||
        !formatedValues.to?.date
      )
        return false;

      return fromHourIsBeforeToHour(
        formatedValues.from?.time,
        formatedValues.to?.time,
      );
    }
    if (hoursRequestType === HoursRequestType.MORE_THAN_ONE_DAY) {
      return areDatesValid(fromDate, toDate);
    }
  }, [
    formatedValues.from?.time,
    formatedValues.to?.time,
    formatedValues.from?.date,
    formatedValues.to?.date,
    hoursRequestType,
  ]);

  const validDayRequest = useMemo(() => {
    if (!formatedValues.from?.date || !formatedValues.to?.date) return false;

    return isBefore(fromDate, toDate) || isEqual(fromDate, toDate);
  }, [
    formatedValues.from?.date,
    formatedValues.to?.date,
    fromDate,
    toDate,
    amountInMoney,
  ]);

  const requestDateRangeComplete = useMemo(() => {
    if (policyType?.unit === UnitVacations.HOURS) {
      return Boolean(validHourRequest);
    }
    if (policyType?.unit === UnitVacations.DAYS) {
      return validDayRequest;
    }
    return false;
  }, [policyType?.unit, validHourRequest, validDayRequest]);

  const {
    requestedDays,
    amountInMoney: amountInMoneyValue,
    amountInTime,
    errors: errorsRequestedDays,
    isLoading: isLoadingRequestedDays,
    warnings: warningsRequestedDays,
  } = useGetRequestedDays({
    ...formatedValues,
    open: openDrawer,
    enabled: requestDateRangeComplete,
  });

  const currentBalance = policyType?.amount || 0;

  const errorInAmountPerRequest = policyType
    ? getErrorInAmountPerRequest(requestedDays, policyType, isManagerRequesting)
    : false;

  const customError = handleCustomErrors(errorsRequestedDays, t);
  const hasErrors =
    errorInAmountPerRequest || Object.keys(errorsRequestedDays).length > 0;

  const disableSubmit =
    !policyType || isLoadingRequestedDays || isSubmitting || hasErrors;

  const requiredFields = Object.keys(errors).length > 0;

  return {
    preview: {
      requestedDays,
      amountInMoney: amountInMoneyValue,
      amountInTime,
      errorsRequestedDays,
      warningsRequestedDays,
      isLoadingRequestedDays,
    },
    footer: {
      errorInAmountPerRequest,
      customError,
      requiredFields,
      currentBalance,
      datesAreSelected: requestDateRangeComplete,
    },
    buttonStates: {
      isSubmitting,
      disableSubmit,
    },
    formatedValues,
  };
};
