import { useMemo, useState } from 'react';
import {
  type DefaultValues,
  FormProvider,
  useForm,
  useWatch,
} from 'react-hook-form';
import { type UseQueryResult } from 'react-query';

import { format } from 'date-fns';
import { fromPairs } from 'lodash-es';
import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import { IconChevronDown, IconSearch } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import Stack from '@material-hu/mui/Stack';

import CollapsibleGroupSelector from '@material-hu/components/composed-components/CollapsibleGroupSelector';
import Accordion from '@material-hu/components/design-system/Accordion';
import Checkbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import FormCheckbox from '@material-hu/components/design-system/Checkbox/Checkbox/form';
import InputClassic from '@material-hu/components/design-system/Inputs/Classic';
import FormDatePicker from '@material-hu/components/design-system/Inputs/DatePicker/form';

import { type SegmentationGroup } from 'src/types/timeTracking';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { type TwoFieldGroup } from 'src/components/AdvancedFilter/types';
import {
  type BaseUser,
  FormUserAutocomplete,
} from 'src/components/dashboard/filterDrawer/FormUserAutocomplete';
import { toCollapsibleSelectorGroups } from 'src/components/dashboard/filterDrawer/toCollapsibleSelectorGroups';

enum FilterOption {
  COLLABORATORS = 'COLLABORATORS',
  HOUR_CATEGORIES = 'HOUR_CATEGORIES',
  DATES = 'DATES',
}

export type ApprovalFiltersFields = {
  users: Array<{ id: number; label: string; value: number }>;
  startDate: Date | null;
  endDate: Date | null;
  hourCategoryIds: Record<string, boolean>;
  segmentationItems: Record<string, boolean>;
  siteIds: Record<string, boolean>;
};

type Props = {
  segmentationGroups: SegmentationGroup[];
  isLoadingSegmentations: boolean;
  regions: TwoFieldGroup[];
  isLoadingRegions: boolean;
  hourCategories: Array<{ id: number; name: string }>;
  isLoadingHourCategories: boolean;
  usersQuery: (search: string) => UseQueryResult<BaseUser[]>;
  usersTotalCount?: number;
  initialValues?: ApprovalFiltersFields;
  onValuesChange?: (v: ApprovalFiltersFields) => void;
};

export const useApprovalFiltersDrawer = (props: Props) => {
  const {
    segmentationGroups,
    isLoadingSegmentations,
    regions,
    isLoadingRegions,
    hourCategories,
    isLoadingHourCategories,
    usersQuery,
    usersTotalCount = 0,
    initialValues,
    onValuesChange,
  } = props;

  const [expandedFilters, setExpandedFilters] = useState<
    Record<FilterOption, boolean>
  >({
    [FilterOption.COLLABORATORS]: false,
    [FilterOption.DATES]: false,
    [FilterOption.HOUR_CATEGORIES]: false,
  });
  const [hourCategoriesSearchQuery, setHourCategoriesSearchQuery] =
    useState('');

  const { t } = useLokaliseTranslation([
    'time_tracker',
    'general',
    'approval_requests',
    'regions_sites',
  ]);

  const handleExpand = (filter: FilterOption, newExpanded: boolean) => {
    setExpandedFilters(prev => ({ ...prev, [filter]: newExpanded }));
  };

  const formInitialValues: DefaultValues<ApprovalFiltersFields> = {
    users: [],
    startDate: null,
    endDate: null,
    hourCategoryIds: hourCategories.reduce(
      (acc, cat) => {
        acc[cat.id.toString()] = false;
        return acc;
      },
      {} as Record<string, boolean>,
    ),
    segmentationItems: segmentationGroups.reduce(
      (acc, group) => {
        group.items.forEach(item => {
          acc[item.value.toString()] = false;
        });
        return acc;
      },
      {} as Record<string, boolean>,
    ),
    siteIds: regions.reduce(
      (acc, group) => {
        group.items.forEach(item => {
          acc[item.value.toString()] = false;
        });
        return acc;
      },
      {} as Record<string, boolean>,
    ),
    ...initialValues,
  };

  const form = useForm<ApprovalFiltersFields>({
    defaultValues: formInitialValues,
  });

  const handleApply = () => {
    const formValues = form.getValues();
    onValuesChange?.(formValues);
  };

  const clearFilters = () => {
    const clearedValues: ApprovalFiltersFields = {
      users: [],
      startDate: null,
      endDate: null,
      hourCategoryIds: hourCategories.reduce(
        (acc, cat) => {
          acc[cat.id.toString()] = false;
          return acc;
        },
        {} as Record<string, boolean>,
      ),
      segmentationItems: segmentationGroups.reduce(
        (acc, group) => {
          group.items.forEach(item => {
            acc[item.value.toString()] = false;
          });
          return acc;
        },
        {} as Record<string, boolean>,
      ),
      siteIds: regions.reduce(
        (acc, group) => {
          group.items.forEach(item => {
            acc[item.value.toString()] = false;
          });
          return acc;
        },
        {} as Record<string, boolean>,
      ),
    };
    form.reset(clearedValues);
    onValuesChange?.(clearedValues);
  };

  const clearDraftValues = () => {
    form.reset(initialValues || formInitialValues);
  };

  // Memoize so we only recompute when form values change. Avoids recalculating
  // on every render (e.g. when drawer state or accordion expand changes) and
  // keeps the derived value in sync with form state via useWatch.
  const watchedValues = useWatch({ control: form.control });
  const hasAppliedFilters: boolean = useMemo(
    () =>
      (watchedValues?.users?.length ?? 0) > 0 ||
      watchedValues?.startDate != null ||
      watchedValues?.endDate != null ||
      Object.values(watchedValues?.hourCategoryIds ?? {}).some(Boolean) ||
      Object.values(watchedValues?.segmentationItems ?? {}).some(Boolean) ||
      Object.values(watchedValues?.siteIds ?? {}).some(Boolean),
    [watchedValues],
  );

  const {
    showDrawer: showFiltersDrawer,
    drawer: filtersDrawer,
    closeDrawer: closeFiltersDrawer,
  } = useDrawerV2(() => {
    const formValues = form.watch();
    const selectedUsersCount = formValues.users?.length || 0;
    const selectedHourCategoriesCount = Object.values(
      formValues.hourCategoryIds || {},
    ).filter(Boolean).length;

    // Helper to check if a date is valid
    const isValidDate = (date: Date | null | string | undefined): boolean => {
      if (!date) return false;
      try {
        const dateObj = date instanceof Date ? date : new Date(date);
        return !Number.isNaN(dateObj.getTime());
      } catch {
        return false;
      }
    };

    const hasDateRange =
      isValidDate(formValues.startDate) || isValidDate(formValues.endDate);

    // Hour categories filtering and selection logic
    const hourCategoryItems = hourCategories.map(cat => ({
      value: cat.id.toString(),
      label: cat.name,
    }));
    const filteredHourCategories = hourCategoryItems.filter(item =>
      item.label
        .toLowerCase()
        .includes(hourCategoriesSearchQuery.toLowerCase()),
    );
    const selectedHourCategories = hourCategoryItems.filter(
      item => formValues.hourCategoryIds?.[item.value],
    );
    const hourCategoriesSelected = () => {
      const totalItems = hourCategoryItems.length;
      return {
        all: selectedHourCategories.length === totalItems,
        some:
          selectedHourCategories.length > 0 &&
          selectedHourCategories.length < totalItems,
      };
    };
    const handleSelectAllHourCategories = () => {
      const availableOptions = hourCategoryItems.map(o => o.value);
      form.setValue('hourCategoryIds', {
        ...formValues.hourCategoryIds,
        ...fromPairs(
          availableOptions.map(o => [o, !hourCategoriesSelected().all]),
        ),
      });
    };

    return {
      children: (
        <FormProvider {...form}>
          <Stack sx={{ overflow: 'auto', flex: 1, gap: 2 }}>
            <Accordion
              title={t('general:collaborators')}
              description={
                selectedUsersCount > 0
                  ? t('general:selected_items', {
                      selected: selectedUsersCount,
                      total: usersTotalCount,
                    })
                  : undefined
              }
              expanded={expandedFilters[FilterOption.COLLABORATORS]}
              onChange={(_, newExpanded) => {
                handleExpand(FilterOption.COLLABORATORS, newExpanded);
              }}
              elevation={0}
              sx={{
                borderRadius: 2,
                backgroundColor: ({ palette }) =>
                  palette.new.background.layout.default,
                '&:before': {
                  backgroundColor: 'transparent',
                },
                '&:first-of-type': {
                  borderTopLeftRadius: 16,
                  borderTopRightRadius: 16,
                  borderBottomLeftRadius: 16,
                  borderBottomRightRadius: 16,
                },
              }}
              disableGutters
              customDetail={
                <FormUserAutocomplete
                  name="users"
                  placeholder={t('general:search')}
                  usersQuery={usersQuery}
                  popupIcon={<IconChevronDown size={24} />}
                  sx={{
                    '.MuiInputAdornment-root .MuiAutocomplete-endAdornment': {
                      right: 16,
                    },
                  }}
                />
              }
            />

            <Accordion
              title={t('approval_requests:date_range')}
              description={
                hasDateRange
                  ? (() => {
                      const formatDate = (
                        date: Date | null | string | undefined,
                      ) => {
                        if (!date) return '';
                        try {
                          const dateObj =
                            date instanceof Date ? date : new Date(date);
                          if (Number.isNaN(dateObj.getTime())) return '';
                          return format(dateObj, 'dd/MM/yyyy');
                        } catch {
                          return '';
                        }
                      };
                      const start = formatDate(formValues.startDate);
                      const end = formatDate(formValues.endDate);
                      return start && end ? `${start} - ${end}` : start || end;
                    })()
                  : undefined
              }
              expanded={expandedFilters[FilterOption.DATES]}
              onChange={(_, newExpanded) => {
                handleExpand(FilterOption.DATES, newExpanded);
              }}
              elevation={0}
              sx={{
                borderRadius: 2,
                backgroundColor: ({ palette }) =>
                  palette.new.background.layout.default,
                '&:before': {
                  backgroundColor: 'transparent',
                },
              }}
              disableGutters
              customDetail={
                <Stack sx={{ gap: 2 }}>
                  <FormDatePicker
                    name="startDate"
                    inputProps={{
                      label: t('general:from'),
                    }}
                  />
                  <FormDatePicker
                    name="endDate"
                    inputProps={{
                      label: t('general:until'),
                    }}
                  />
                </Stack>
              }
            />

            <Accordion
              title={t('time_tracker:include_hour_types')}
              description={
                selectedHourCategoriesCount > 0
                  ? selectedHourCategories.map(item => item.label).join(', ')
                  : undefined
              }
              expanded={expandedFilters[FilterOption.HOUR_CATEGORIES]}
              onChange={(_, newExpanded) => {
                handleExpand(FilterOption.HOUR_CATEGORIES, newExpanded);
              }}
              elevation={0}
              sx={{
                borderRadius: 2,
                backgroundColor: ({ palette }) =>
                  palette.new.background.layout.default,
                '&:before': {
                  backgroundColor: 'transparent',
                },
              }}
              disableGutters
              customDetail={
                <Stack sx={{ width: '100%', gap: 2 }}>
                  <InputClassic
                    placeholder={t('general:search')}
                    value={hourCategoriesSearchQuery}
                    hasCounter={false}
                    onChange={value => setHourCategoriesSearchQuery(value)}
                    startAdornment={<IconSearch size={20} />}
                    sx={{
                      backgroundColor: ({ palette }) =>
                        palette.new.background.layout.tertiary,
                    }}
                  />
                  <Box
                    sx={{
                      backgroundColor: ({ palette }) =>
                        palette.new.background.layout.tertiary,
                      borderRadius: 2,
                      p: 2,
                      maxHeight: 200,
                      overflow: 'auto',
                    }}
                  >
                    <Stack sx={{ gap: 3 }}>
                      {hourCategoryItems.length > 1 &&
                        !hourCategoriesSearchQuery && (
                          <Checkbox
                            label={t('select_all')}
                            onChange={handleSelectAllHourCategories}
                            checked={hourCategoriesSelected().all}
                            indeterminate={hourCategoriesSelected().some}
                          />
                        )}
                      {isLoadingHourCategories ? (
                        <Stack sx={{ gap: 2 }}>
                          {[1, 2, 3].map(i => (
                            <Stack
                              key={i}
                              sx={{ height: 28, width: '100%' }}
                            />
                          ))}
                        </Stack>
                      ) : (
                        filteredHourCategories.map(item => (
                          <FormCheckbox
                            key={item.value}
                            name={`hourCategoryIds.${item.value}`}
                            checkBoxProps={{
                              label: item.label,
                            }}
                          />
                        ))
                      )}
                    </Stack>
                  </Box>
                </Stack>
              }
            />

            <CollapsibleGroupSelector
              sx={{ '& .MuiTypography-root': { mb: 0 } }}
              groups={toCollapsibleSelectorGroups(segmentationGroups ?? [])}
              isLoading={isLoadingSegmentations}
              fieldName="segmentationItems"
              title={t('general:segmentations')}
            />
            <CollapsibleGroupSelector
              sx={{ '& .MuiTypography-root': { mb: 0 }, mt: 2 }}
              groups={toCollapsibleSelectorGroups(regions ?? [])}
              isLoading={isLoadingRegions}
              fieldName="siteIds"
              title={t('regions_sites:sites')}
            />
          </Stack>
        </FormProvider>
      ),
      title: t('general:filter_by'),
      onClose: () => {
        clearDraftValues();
        closeFiltersDrawer();
      },
      primaryButtonProps: {
        children: t('general:apply'),
        fullWidth: true,
        onClick: () => {
          handleApply();
          closeFiltersDrawer();
        },
      },
      secondaryButtonProps: {
        children: t('general:clean_selection'),
        fullWidth: true,
        onClick: clearFilters,
        disabled: !hasAppliedFilters,
      },
    };
  });

  return {
    showFiltersDrawer,
    filtersDrawer,
    closeFiltersDrawer,
    formValues: form.watch(),
  };
};
