import {useContext, useContextSection, usePreloadSettingData} from '@hooks';
import {Dispatch, useCallback, useReducer} from 'react';
import {createContext} from 'use-context-selector';

export type SearchContextState = {
  isSearching: boolean;
  refetch: () => void;
  conditions: string;
  tableWidth: string;
  tableOrder: string;
};

export type SearchContextAction =
  | {type: 'CHANGE_SEARCH_STATE'; payload: boolean}
  | {type: 'CHANGE_SEARCH_FUNCTION'; payload: () => void}
  | {
      type: 'CHANGE_VALUE';
      payload: {
        key: keyof Omit<SearchContextState, 'isSearching' | 'refetch'>;
        value: string;
      };
    };

export function initSearchContextState(
  init?: Partial<SearchContextState>,
): SearchContextState {
  const {
    isSearching = false,
    conditions = '',
    tableOrder = '',
    tableWidth = '',
  } = init ?? {};

  return {
    isSearching,
    refetch: () => null,
    conditions,
    tableOrder,
    tableWidth,
  };
}

function reducer(
  state: SearchContextState,
  action: SearchContextAction,
): SearchContextState {
  switch (action.type) {
    case 'CHANGE_SEARCH_STATE':
      return {...state, isSearching: action.payload};
    case 'CHANGE_SEARCH_FUNCTION':
      return {...state, refetch: action.payload};
    case 'CHANGE_VALUE':
      return {...state, [action.payload.key]: action.payload.value};
    default:
      return state;
  }
}

export function useSearchContextReducer(preloadKey?: string) {
  const preloadData = usePreloadSettingData(preloadKey);

  return useReducer(reducer, initSearchContextState(preloadData ?? {}));
}

export const createSearchContext = () =>
  createContext<[SearchContextState, Dispatch<SearchContextAction>]>([
    initSearchContextState(),
    () => null,
  ]);

export function useTableSearchState(
  context: ReturnType<typeof createSearchContext>,
) {
  const [{isSearching}, dispatch] = useContext(context);

  const onSearchChange = useCallback(
    function (state: boolean) {
      dispatch({type: 'CHANGE_SEARCH_STATE', payload: state});
    },
    [dispatch],
  );

  return [isSearching, onSearchChange] as const;
}

export function useTableSearchDispatch(
  context: ReturnType<typeof createSearchContext>,
) {
  const [, dispatch] = useContext(context);

  return dispatch;
}

export function useTableStateContext(
  context: ReturnType<typeof createSearchContext>,
) {
  const state = useContextSection(context, ([state]) => ({
    tableOrder: state.tableOrder,
    tableWidth: state.tableWidth,
  }));
  const dispatch = useTableSearchDispatch(context);

  const setTableWidth = useCallback(
    function (value: string) {
      dispatch({type: 'CHANGE_VALUE', payload: {key: 'tableWidth', value}});
    },
    [dispatch],
  );

  const setTableOrder = useCallback(
    function (value: string) {
      dispatch({type: 'CHANGE_VALUE', payload: {key: 'tableOrder', value}});
    },
    [dispatch],
  );

  return [state, {setTableOrder, setTableWidth}] as const;
}

export function useTableFilterState(
  context: ReturnType<typeof createSearchContext>,
) {
  const filter = useContextSection(context, state => state[0].conditions);

  const dispatch = useTableSearchDispatch(context);

  const setFilter = useCallback(
    function (value: string) {
      dispatch({type: 'CHANGE_VALUE', payload: {key: 'conditions', value}});
    },
    [dispatch],
  );

  return [filter, setFilter] as const;
}
