import { createReducer, Action, on } from '@ngrx/store';
import { INITIAL_SEARCH_STATE, SearchState, searchStateAdapter, INITIAL_SEARCH_PROCESS } from './search.state';
import * as actions from './search.actions';
import { SearchProcessState } from './defs';

const _searchReducer = createReducer(
  INITIAL_SEARCH_STATE,
  on(actions.cleanup, (s) =>
    Object.values(s.entities).reduce(
      (state, process) => searchStateAdapter.updateOne({ id: process.id, changes: { result: [] } }, state),
      s
    )
  ),
  on(actions.addSearchProcess, (s, a) => searchStateAdapter.addOne({ ...INITIAL_SEARCH_PROCESS, id: a.id }, s)),
  on(actions.removeSearchProcess, (s, a) => searchStateAdapter.removeOne(a.id, s)),
  on(actions.setInput, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { input: a.input } }, s)),
  on(actions.setSelectFilters, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          filters: {
            ...s.entities[a.id].filters,
            selectedFilters: a.filters,
          },
        },
      },
      s
    )
  ),
  on(actions.setPrimaryFilters, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          filters: { ...s.entities[a.id].filters, primaryFilters: a.filters },
        },
      },
      s
    )
  ),
  on(actions.resetSelectFilters, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          filters: {
            ...s.entities[a.id].filters,
            selectedFilters: s.entities[a.id].filters.selectedFilters.map((filter) => {
              let options = filter.options || [];
              if (filter.options) {
                options = filter.options.map((o) => ({
                  ...o,
                  selected: o.initial_selected_state,
                }));
              }

              return { ...filter, options };
            }),
          },
        },
      },
      s
    )
  ),
  on(actions.resetPrimaryFilters, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          filters: {
            ...s.entities[a.id].filters,
            primaryFilters: s.entities[a.id].filters.primaryFilters.map((primaryFilter) => ({
              ...primaryFilter,
              selected: primaryFilter.initial_selected_state,
            })),
          },
        },
      },
      s
    )
  ),
  on(actions.clearError, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          state: SearchProcessState.INIT,
        },
      },
      s
    )
  ),
  on(actions.clearResults, (s, a) =>
    searchStateAdapter.updateOne({ id: a.id, changes: { result: [], state: SearchProcessState.INIT } }, s)
  ),
  on(actions.addResult, (s, a) => {
    const addSubsetIds = a.result.map((item) => item.orderItemSubsetId);
    const entitiesWithoutDublicatedItems = s.entities[a.id].result.filter(
      (item) => !addSubsetIds.some((id) => id === item.orderItemSubsetId)
    );

    return searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: {
          result: [...entitiesWithoutDublicatedItems, ...a.result],
          state: SearchProcessState.FETCHED,
        },
      },
      s
    );
  }),
  on(actions.clearHits, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { hits: undefined } }, s)),
  on(actions.setHits, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { hits: a.hits } }, s)),
  on(actions.setTimestamp, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: { timestamp: Date.now() },
      },
      s
    )
  ),
  on(actions.fetchResult, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { state: SearchProcessState.FETCHING } }, s)),
  on(actions.fetchResultDone, (s, a) => searchStateAdapter.updateOne({ id: a.id, changes: { state: SearchProcessState.FETCHED } }, s)),
  on(actions.setPendingInput, (s, a) =>
    searchStateAdapter.updateOne(
      {
        id: a.id,
        changes: { pendingInput: a.input },
      },
      s
    )
  )
);

export function searchReducer(state: SearchState, action: Action) {
  return _searchReducer(state, action);
}
