import { useCallback, useMemo } from 'react';
import { useConfig, useFilterData } from '@assets/filters/state';
import { findParameterConfig } from '@assets/filters/parameters/findParameterConfig';
import { trackListParameterChange } from '@assets/filters/parameters/list/trackListParameterChange';
import type { ParameterFilterProps } from '@assets/filters/parameters/list/ListParameterFilter';
import type { SelectedListParameter } from '@assets/filters/parameters/filterDataSlice';

/**
 * 1) Get the data necessary to render a MultiChoiceFilter for a list parameter.
 * 2) Registers a listener for GraphQL response and updates the config context with new product counts.
 * 3) Sends GTM tracking events when something changes.
 *
 * @throws Error when:
 *    - parameter with the specified id is not found,
 *    - or the parameter with the specified id is not a `list` parameter.
 */
export function useListParameter(parameterId: ParameterFilterProps<'multi-choice'>['parameterId']) {
   const { parameters } = useConfig();
   const { filterData, setFilterData } = useFilterData();

   const config = useMemo(
      () => findParameterConfig(parameterId, 'list', parameters ?? []),
      [parameters, parameterId],
   );

   const selected = useMemo(() => {
      const parameter = filterData?.parameters?.[parameterId]?.value || [];

      return (parameter as SelectedListParameter['value']).map(Number);
   }, [filterData, parameterId]);

   const setSelected = useCallback((newSelected: number[]) => {
      trackListParameterChange(
         config,
         selected,
         newSelected
      );

      if (newSelected.length === 0) {
         const newParameters = { ...filterData.parameters };
         delete newParameters[parameterId];

         // No parameter filters are selected -> remove key `parameters` from filterData
         if (Object.keys(newParameters).length === 0) {
            setFilterData(old => {
               const newState = { ...old };
               delete newState.parameters;

               return newState;
            });

            return;
         }

         setFilterData(old => ({
            ...old,
            parameters: newParameters,
         }));

         return;
      }

      setFilterData(old => ({
         ...old,
         parameters: {
            ...(old.parameters ?? {}),
            [parameterId]: {
               type: 'list',
               value: newSelected,
            },
         },
      }));
   }, [parameterId, selected, setFilterData]);

   return {
      selected,
      setSelected,
      config,
   };
}
