import { Reducer, useEffect, useReducer, useState } from 'react';
import { Data } from '../../../types';
import {
  DynamicListReducer,
  DynamicListReducerAction,
  DynamicListReducerActionType,
  DynamicListReducerInit,
  DynamicListReducerInitArgs,
  DynamicListReducerState,
} from './DynamicListReducer';

export const useDataHandler = <T extends Data>(
  initialValue: T[],
  positionPropertyName: keyof T | undefined,
  maxItemLimit: number | undefined,
  allowNewData: boolean,
  onChange: (value: T[]) => void,
  onAddTransformData?: (data: Partial<T>) => T,
): {
  readonly items: T[];
  readonly nextPosition: number;
  readonly canAddItems: boolean;
  readonly addItem: (item: T) => void;
  readonly removeItem: (item: T) => void;
  readonly updateItem: (currentItem: T, newItem: T) => void;
} => {
  const [shouldTriggerOnChange, setShouldTriggerOnChange] = useState(false);

  const [state, dispatch] = useReducer<
    Reducer<DynamicListReducerState<T>, DynamicListReducerAction<T>>,
    DynamicListReducerInitArgs<T>
  >(
    DynamicListReducer,
    {
      initialValue,
      positionPropertyName,
      maxItemLimit,
      allowNewData,
    },
    DynamicListReducerInit,
  );

  useEffect(() => {
    // Reset the reducer data to new initial value
    dispatch({
      type: DynamicListReducerActionType.Reset,
      items: initialValue,
      positionPropertyName,
      maxItemLimit,
      allowNewData,
    });
  }, [allowNewData, initialValue, maxItemLimit, positionPropertyName]);

  useEffect(() => {
    // This is to prevent the onChange from being triggered on the initial render
    if (shouldTriggerOnChange) {
      onChange(state.items);
      setShouldTriggerOnChange(false);
    }
  }, [onChange, shouldTriggerOnChange, state.items]);

  const addItem = (item: T): void => {
    dispatch({
      type: DynamicListReducerActionType.Add,
      item: onAddTransformData ? onAddTransformData(item) : item,
    });
    setShouldTriggerOnChange(true);
  };

  const removeItem = (item: T): void => {
    dispatch({ type: DynamicListReducerActionType.Remove, item });
    setShouldTriggerOnChange(true);
  };

  const updateItem = (currentItem: T, newItem: T): void => {
    dispatch({
      type: DynamicListReducerActionType.Update,
      currentItem,
      newItem,
    });
    setShouldTriggerOnChange(true);
  };

  const { items, nextPosition, canAddItems } = state;

  return { items, nextPosition, canAddItems, addItem, removeItem, updateItem };
};
