import { type FC, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useQuery } from 'react-query';

import { pickBy } from 'lodash-es';
import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import { useModal } from '@material-hu/hooks/useModal';

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

import { logEvent } from 'src/config/logging';
import { FileExtensions } from 'src/constants/filesPreview';
import { useAuth } from 'src/contexts/JWTContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import { profileKeys } from 'src/pages/dashboard/profile/queries';
import {
  getHourCategories,
  prepareReportEmail,
} from 'src/services/timeTracking';
import { dynamicFieldsResponse } from 'src/services/users';
import { EventName } from 'src/types/amplitude';
import {
  type ReportDownloadFields,
  type ReportFilterFields,
  ReportType,
} from 'src/types/timeTracking';
import { formatUTCDate } from 'src/utils/date';
import { useLokaliseTranslation } from 'src/utils/i18n';
import {
  formatCommonReportParams,
  getUserFields,
} from 'src/utils/timeTracking';

import {
  type AutocompleteField,
  ProfileField,
} from 'src/components/AdvancedFilter/types';
import { getAllProfileFields } from 'src/components/AdvancedFilter/utils';

import DownloadingReportModal from '../../../DownloadingReportModal';
import { timeTrackingKeys } from '../../../queries';

import ReportFieldsStep from './ReportFieldsStep';
import ReportSettingsStep from './ReportSettingsStep';

export type ReportProps = {
  open: boolean;
  onClose: () => void;
  segmentationGroups: AutocompleteField[];
  isLoadingSegmentations: boolean;
  appliedFilters: ReportFilterFields;
  reportUsersCount: number;
  fromDate: Date;
  toDate: Date;
  search: string;
};

const ReportDownload: FC<ReportProps> = props => {
  const {
    appliedFilters,
    isLoadingSegmentations,
    open,
    onClose,
    segmentationGroups,
    reportUsersCount,
    fromDate,
    toDate,
    search,
  } = props;
  const { t } = useLokaliseTranslation('time_tracker');
  const { user, instance } = useAuth();
  const { enqueueSnackbar } = useHuSnackbar();
  const showGeneralError = useGeneralError();
  const HuGoThemeProvider = useHuGoTheme();

  const formInitialValues: ReportDownloadFields = {
    email: user?.email || '',
    enableProfileFields: false,
    enableSegmentationGroups: false,
    enableHourTypes: false,
    segmentationGroups: [],
    profileFields: [],
    hourTypes: {},
    reportType: ReportType.CONSOLIDATED,
    fileExtension: FileExtensions.XLSX,
    // Detailed report options
    includeScheduledTime: false,
    includeClockInOut: false,
    includeAutoCloseIncidence: false,
    includeKiosk: false,
  };

  const form = useForm<ReportDownloadFields>({
    defaultValues: formInitialValues,
  });
  const {
    formState: { isSubmitting },
    handleSubmit,
    reset,
  } = form;
  const { email, reportType } = form.watch();

  // Stepper state
  const [currentStep, setCurrentStep] = useState(0);
  const totalSteps = 2;

  const handleOnClose = () => {
    onClose();
    // Storing default values on a variable because reset() won't clean all the fields
    reset(formInitialValues);
    setCurrentStep(0);
  };

  const handleNextStep = async () => {
    // Validate email before going to next step
    const isValid = await form.trigger(['email', 'reportType']);
    if (isValid) {
      setCurrentStep(prev => Math.min(prev + 1, totalSteps - 1));
    }
  };

  const handlePreviousStep = () => {
    // Reset step 2 fields when going back
    reset(prevValues => ({
      ...prevValues,
      enableProfileFields: false,
      enableSegmentationGroups: false,
      enableHourTypes: false,
      segmentationGroups: [],
      profileFields: [],
      hourTypes: {},
      includeScheduledTime: false,
      includeClockInOut: false,
      includeAutoCloseIncidence: false,
      includeKiosk: false,
    }));
    setCurrentStep(prev => Math.max(prev - 1, 0));
  };

  const { data: profileFields = [], isLoading: isLoadingProfileFields } =
    useQuery(
      profileKeys.userProfileData(user!.id, instance!.id),
      () => dynamicFieldsResponse(instance!.id),
      {
        select: response => {
          return [
            ...getAllProfileFields(t).filter(
              o => o.value !== ProfileField.EMPLOYEE_INTERNAL_ID,
            ),
            ...Object.entries(response.data).map(([key, v]) => ({
              value: key,
              label: v.name,
            })),
          ];
        },
        onError: () => {
          enqueueSnackbar({
            title: t('error_loading_profile_fields'),
            variant: 'error',
          });
        },
      },
    );

  const { data: hourCategories = [], isLoading: isLoadingHourCategories } =
    useQuery(
      timeTrackingKeys.hourCategories(),
      () => getHourCategories({ page: 1, limit: 100, search: '' }),
      {
        select: response =>
          response.data.items.map(hour => ({
            value: hour.id,
            label: hour.name,
          })),
        onError: () => {
          enqueueSnackbar({
            title: t('error_loading_hour_categories'),
            variant: 'error',
          });
        },
      },
    );

  const { isFetching: isFetchingReport, refetch: sendReport } = useQuery({
    queryKey: timeTrackingKeys.registersReport(),
    queryFn: () => {
      const formValues = form.getValues();
      const reportParams = formatCommonReportParams({
        fromDate,
        toDate,
        reportFilters: appliedFilters,
      });
      const profileFieldsValues = formValues.profileFields.reduce(
        (acc, { value }) => ({ ...acc, [`${value}`]: true }),
        { EMPLOYEE_INTERNAL_ID: true },
      );
      const selectedProfileFields = getUserFields(
        Object.keys(pickBy(profileFieldsValues)),
      );
      return prepareReportEmail({
        ...reportParams,
        search: search,
        userFields: selectedProfileFields.userFields,
        userCustomFields: selectedProfileFields.userCustomFields,
        segmentationGroups: formValues.segmentationGroups
          .map(group => group.value)
          .join(),
        hourCategoryIds: Object.keys(pickBy(formValues.hourTypes)).join(','),
        reportType: reportType,
        email: email,
        includeScheduledTime: formValues.includeScheduledTime,
        includeClockInOut: formValues.includeClockInOut,
        includeAutoCloseIncidence: formValues.includeAutoCloseIncidence,
        includeKiosk: formValues.includeKiosk,
      });
    },
    onSuccess: () => {
      enqueueSnackbar({
        title: t('check_mail'),
        description: t('delivery_hint', { email }),
        variant: 'success',
      });
      const {
        enableProfileFields,
        enableSegmentationGroups,
        enableHourTypes,
        includeScheduledTime,
        includeClockInOut,
        includeAutoCloseIncidence,
        includeKiosk,
      } = form.getValues();
      const toggableFields = {
        SEGMENTATIONS: enableSegmentationGroups,
        USER_FIELDS: enableProfileFields,
        HOURS_TYPE: enableHourTypes,
        SCHEDULE: includeScheduledTime,
        CLOCK_METHOD: includeClockInOut,
        MISSED_PUNCH: includeAutoCloseIncidence,
        KIOSK_TERMINAL: includeKiosk,
      };
      logEvent(EventName.TIME_TRACKING_REPORT_DOWNLOADED, {
        reportType: reportType,
        startDate: formatUTCDate(fromDate),
        endDate: formatUTCDate(toDate),
        userCount: reportUsersCount,
        fields: Object.keys(toggableFields).filter(
          field => toggableFields[field as keyof typeof toggableFields],
        ),
      });
      handleOnClose();
    },
    onError: err => {
      showGeneralError(err, t('report_download_error'));
    },
    onSettled: () => {
      closeDownloadingReportModal();
    },
    enabled: false,
  });

  const {
    modal: downloadingReportModal,
    showModal: showDownloadingReportModal,
    closeModal: closeDownloadingReportModal,
  } = useModal(
    () => <DownloadingReportModal onClose={closeDownloadingReportModal} />,
    {
      maxWidth: 'xs',
      fullWidth: true,
    },
  );

  const handleDownloadReport = () => {
    showDownloadingReportModal();
    sendReport();
  };

  const isLastStep = currentStep === totalSteps - 1;

  const { drawer } = useDrawerV2(() => ({
    title: t('download_report'),
    children: (
      <FormProvider {...form}>
        {currentStep === 0 ? (
          <ReportSettingsStep />
        ) : (
          <ReportFieldsStep
            segmentationGroups={segmentationGroups}
            profileFields={profileFields}
            hourTypes={hourCategories}
          />
        )}
      </FormProvider>
    ),
    onClose: handleOnClose,
    open,
    primaryButtonProps: isLastStep
      ? {
          children: t('download'),
          onClick: handleSubmit(handleDownloadReport),
          variant: 'primary',
          loading: isSubmitting || isFetchingReport,
          disabled:
            isSubmitting ||
            isLoadingSegmentations ||
            isFetchingReport ||
            isLoadingProfileFields ||
            isLoadingHourCategories,
          fullWidth: true,
        }
      : {
          children: t('general:next'),
          onClick: handleNextStep,
          variant: 'primary',
          fullWidth: true,
        },
    secondaryButtonProps: isLastStep
      ? {
          children: t('general:back'),
          onClick: handlePreviousStep,
          variant: 'tertiary',
          fullWidth: true,
        }
      : {
          children: t('general:cancel'),
          onClick: handleOnClose,
          variant: 'tertiary',
          fullWidth: true,
        },
  }));

  return (
    <HuGoThemeProvider>
      {downloadingReportModal}
      {drawer}
    </HuGoThemeProvider>
  );
};

export default ReportDownload;
