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

import { zodResolver } from '@hookform/resolvers/zod';
import { type AxiosResponse } from 'axios';
import { type TFunction } from 'i18next';

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

import { useAuth } from 'src/contexts/JWTContext';
import useGeneralError from 'src/hooks/useGeneralError';
import { profileKeys } from 'src/pages/dashboard/profile/queries';
import {
  calculateActiveCollaboratorFiltersCount,
  getDefaultUserEmail,
  parseReportFilters,
} from 'src/pages/dashboard/serviceManagement/utils';
import {
  downloadConsolidatedReport,
  downloadServiceReport,
} from 'src/pages/dashboard/serviceManagement/services';
import {
  type CoordinatorTaskFilters,
  type DownloadTasksReportFormValues,
  type FilterFormValues,
  type ServiceManagementRole,
  type ServiceReportParsedFilters,
  TaskReportType,
} from 'src/pages/dashboard/serviceManagement/types';
import { getSegmentationGroups } from 'src/services/segmentations';
import { dynamicFieldsResponse } from 'src/services/users';
import { Visibility } from 'src/types/instance';
import { type Segmentation } from 'src/types/segmentation';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  defaultTaskFilters,
  FILTERS_DEFAULT_VALUES,
  UserFields,
} from '../constants';
import { tasksReportFormFields } from '../form/form';
import {
  createCoordinatorFiltersSchema,
  downloadTicketsReportSchema,
} from '../form/schemas';
import { type FilterType } from '../types';
import { getDateFilterThresholdStatus } from '../utils';

const MAX_MONTHS_FOR_DOWNLOAD = 6;

type UseReportDownloadParams = {
  open: boolean;
  onClose: () => void;
  appliedFilters: CoordinatorTaskFilters | FilterFormValues | null;
  appliedFiltersCount: number;
  helpDeskId?: string | null;
  filterType?: FilterType;
  role: ServiceManagementRole;
};

export const useReportDownload = ({
  open,
  onClose,
  appliedFilters,
  appliedFiltersCount,
  helpDeskId,
  filterType = 'agent',
  role,
}: UseReportDownloadParams) => {
  const { t } = useLokaliseTranslation(['service_management', 'users']);
  const { enqueueSnackbar: showSnackbar } = useSnackbar();
  const { instance, user } = useAuth();
  const showGeneralError = useGeneralError();

  const [filtersDrawerOpen, setFiltersDrawerOpen] = useState(false);
  const [localFilters, setLocalFilters] = useState<
    CoordinatorTaskFilters | FilterFormValues | null
  >(appliedFilters);
  const [localFiltersCount, setLocalFiltersCount] =
    useState<number>(appliedFiltersCount);

  const defaultFilterValues =
    filterType === 'coordinator' ? defaultTaskFilters : FILTERS_DEFAULT_VALUES;

  const agentFiltersForm = useForm<FilterFormValues>({
    defaultValues: FILTERS_DEFAULT_VALUES,
    resolver: zodResolver(createCoordinatorFiltersSchema(t as TFunction)),
    mode: 'onChange',
  });

  const coordinatorFiltersForm = useForm<CoordinatorTaskFilters>({
    defaultValues: defaultTaskFilters,
    resolver: zodResolver(createCoordinatorFiltersSchema(t as TFunction)),
    mode: 'onChange',
  });

  const localFiltersForm =
    filterType === 'coordinator' ? coordinatorFiltersForm : agentFiltersForm;

  const form = useForm<DownloadTasksReportFormValues>({
    defaultValues: {
      email: getDefaultUserEmail(user),
      reportType: TaskReportType.CONSOLIDATED,
      includeSegmentations: false,
      includeProfileFields: false,
      segmentations: [],
      profileFields: [],
    },
    resolver: zodResolver(downloadTicketsReportSchema()),
    mode: 'onChange',
  });

  const [
    selectedReportType,
    includeSegmentationsValue,
    includeProfileFieldsValue,
    selectedSegmentations = [],
    selectedProfileFields = [],
  ] = useWatch({
    control: form.control,
    name: [
      tasksReportFormFields.reportType(),
      tasksReportFormFields.includeSegmentations(),
      tasksReportFormFields.includeProfileFields(),
      tasksReportFormFields.segmentations(),
      tasksReportFormFields.profileFields(),
    ],
  });

  useEffect(() => {
    if (open) {
      setLocalFilters(appliedFilters);
      setLocalFiltersCount(appliedFiltersCount);
      localFiltersForm.reset({
        ...defaultFilterValues,
        ...appliedFilters,
      } as typeof defaultFilterValues);
    }
  }, [
    open,
    appliedFilters,
    appliedFiltersCount,
    localFiltersForm,
    defaultFilterValues,
  ]);

  const handleOpenFiltersDrawer = useCallback(() => {
    setFiltersDrawerOpen(true);
  }, []);

  const handleCloseFiltersDrawer = useCallback(() => {
    localFiltersForm.reset({
      ...defaultFilterValues,
      ...localFilters,
    } as typeof defaultFilterValues);
    setFiltersDrawerOpen(false);
  }, [localFilters, localFiltersForm, defaultFilterValues]);

  const handleApplyLocalFilters = useCallback(() => {
    const filterValues = localFiltersForm.getValues();
    setLocalFilters(filterValues);
    setLocalFiltersCount(
      calculateActiveCollaboratorFiltersCount(
        filterValues as unknown as Partial<CoordinatorTaskFilters>,
      ),
    );
    setFiltersDrawerOpen(false);
  }, [localFiltersForm]);

  const handleResetLocalFiltersForm = useCallback(() => {
    localFiltersForm.reset(defaultFilterValues as typeof defaultFilterValues);
  }, [localFiltersForm, defaultFilterValues]);

  const { data: dataSegmentations, isLoading: loadingSegmentations } = useQuery(
    ['tasks-report-segmentations'],
    () => getSegmentationGroups(),
    {
      select: (response: AxiosResponse<Segmentation[]>) => [
        ...response.data.filter(
          elem => elem.items.length > 0 && elem.visibility === Visibility.ALL,
        ),
      ],
      enabled: open,
      refetchOnMount: false,
    },
  );

  const { data: profileFields, isLoading: isLoadingProfileFields } = useQuery(
    profileKeys.profileFields(instance?.id ?? 0),
    () => dynamicFieldsResponse(instance?.id ?? 0),
    {
      select: response => [
        ...Object.values(UserFields).map(val => ({
          id: val,
          name: t(`users:user_fields.${val.toLowerCase()}`),
        })),
        ...Object.entries(response.data).map(([key, v]) => ({
          id: key,
          name: v.name,
        })),
      ],
      enabled: open,
      refetchOnMount: false,
    },
  );

  const profileFieldsOptions = useMemo(
    () => profileFields?.map(f => ({ ...f, label: f.name, value: f.id })) || [],
    [profileFields],
  );

  const reportMutationOptions = useMemo(
    () => ({
      onSuccess: (_: AxiosResponse, filters: ServiceReportParsedFilters) => {
        showSnackbar({
          title: t('report_download_success_title'),
          description: t('report_download_success_description', {
            email: filters.destinationEmails[0] ?? '',
          }),
          variant: 'success',
        });
        form.reset();
        onClose();
      },
      onError: (err: unknown) => {
        showGeneralError(err, t('report_download_error'));
      },
    }),
    [showSnackbar, t, form, onClose, showGeneralError],
  );

  const {
    mutate: downloadServiceReportMutation,
    isLoading: isDownloadingServiceReport,
  } = useMutation(
    (filters: ServiceReportParsedFilters) =>
      downloadServiceReport(filters, role),
    reportMutationOptions,
  );

  const {
    mutate: downloadConsolidatedReportMutation,
    isLoading: isDownloadingConsolidatedReport,
  } = useMutation(
    (filters: ServiceReportParsedFilters) =>
      downloadConsolidatedReport(filters, role),
    reportMutationOptions,
  );

  const dateFilterThresholdStatus = useMemo(
    () => getDateFilterThresholdStatus(localFilters),
    [localFilters],
  );

  const dateFiltersExceedThreshold = dateFilterThresholdStatus.exceeds;

  const segmentationOptions = useMemo(
    () =>
      dataSegmentations?.map(s => ({ ...s, label: s.name, value: s.id })) || [],
    [dataSegmentations],
  );

  const getAlertTitleProps = useCallback(() => {
    let title: string;
    let description: string;

    if (dateFiltersExceedThreshold) {
      title =
        dateFilterThresholdStatus.reason === 'from_only'
          ? t('download_time_limit_alert_from_title', {
              count: MAX_MONTHS_FOR_DOWNLOAD,
            })
          : t('download_time_limit_alert_title', {
              count: MAX_MONTHS_FOR_DOWNLOAD,
            });
      description = t('download_time_limit_alert_description');
    } else {
      title = t('applied_filters_count', { count: localFiltersCount });
      description = t('applied_filters_report_description');
    }

    return {
      severity:
        dateFiltersExceedThreshold && localFiltersCount > 0
          ? ('warning' as const)
          : ('info' as const),
      title,
      description,
      action: { text: t('update_filters'), onClick: handleOpenFiltersDrawer },
    };
  }, [
    dateFiltersExceedThreshold,
    dateFilterThresholdStatus.reason,
    localFiltersCount,
    t,
    handleOpenFiltersDrawer,
  ]);

  const handleDownload = () => {
    const parsedFilters = parseReportFilters(
      form.getValues(),
      localFilters,
      helpDeskId,
    );
    if (selectedReportType === TaskReportType.CONSOLIDATED) {
      downloadConsolidatedReportMutation(parsedFilters);
    } else {
      downloadServiceReportMutation(parsedFilters);
    }
  };

  const handleResetFilters = () => {
    form.reset();
    setLocalFilters(null);
    setLocalFiltersCount(0);
    localFiltersForm.reset(defaultFilterValues as typeof defaultFilterValues);
  };

  const missingSelections =
    (includeSegmentationsValue && selectedSegmentations.length === 0) ||
    (includeProfileFieldsValue && selectedProfileFields.length === 0);

  const isLoadingDownload =
    isDownloadingServiceReport || isDownloadingConsolidatedReport;

  return {
    form,
    agentFiltersForm,
    coordinatorFiltersForm,
    filtersDrawerOpen,
    selectedReportType,
    includeSegmentationsValue,
    includeProfileFieldsValue,
    selectedSegmentations,
    selectedProfileFields,
    loadingSegmentations,
    dataSegmentations,
    isLoadingProfileFields,
    profileFieldsOptions,
    segmentationOptions,
    getAlertTitleProps,
    handleOpenFiltersDrawer,
    handleCloseFiltersDrawer,
    handleApplyLocalFilters,
    handleResetLocalFiltersForm,
    handleDownload,
    handleResetFilters,
    missingSelections,
    isLoadingDownload,
  };
};
