/* eslint-disable eqeqeq */
import { isEmpty, isArray } from '@/helpers'

export const namespaced = true

export const state = () => ({
  hits: [],
  queryId: '',
  segments: [],
  keyword: '',
  pageId: 0,
  aggregations: [],
  pagination: {},
  selections: [],
  filters: [],
  sorting: [],
  paging: [],
  banners: [],
  layout: null,
  toggleLayout: false,
  sort: undefined,
  pageSize: undefined,
  page: 1,
  overlay: false,
  primaryKey: null,
  events: [],
  complete: '',
  suggestResult: {},
  suggestItems: {},
  currentSuggestion: null,
  context: {},
  fallbackMode: false,
  gridItem: '',
  listItem: '',
  css: '',
  config: {},
  queryParam: 'q',
  pageParam: 'page',
  translation: undefined,
  filterLayout: 'vertical',
  redirect: undefined
})

export const mutations = {
  LOAD_BANNERS(state, data) {
    state.banners = data
  },
  LOAD_CONFIG(state, data) {
    state.config = data.autocomplete
    state.translation = data.translation
  },
  RUN_AUTOCOMPLETE(state, payload) {
    if (payload.includeSuggestResult) {
      state.suggestResult = payload.data.suggestResult
      state.currentSuggestion = payload.data.suggestion
      state.complete = payload.data.complete
    }
    state.suggestItems = payload.data.searchResult
    state.primaryKey = payload.primaryKey
    state.redirect = payload.data.searchResult.redirect
  },
  RUN_QUERY(state, data) {
    const pagingType = data.pagination.pagingType
    if (data.pagination.current_page == 1) {
      state.hits = data.hits
    } else {
      if (pagingType === 'more' || pagingType === 'infinite') {
        state.hits.items.push(...data.hits.items)
      } else {
        state.hits = data.hits
      }
    }
    state.queryId = data.queryId
    state.segments = data.segments
    state.primaryKey = data.primaryKey
    // add .state and .open properties
    data.aggregations.forEach(agg => {
      agg.state = {}
      agg.open = {}
    })

    // flatten tree aggregations to simplify value lookup
    const flat = {}
    const flatten = (name, item) => {
      flat[name] = flat[name] || {}
      flat[name][item.key] = item
      if (item.children) {
        item.children.forEach(child => flatten(name, child))
      }
    }
    data.aggregations
      .filter(y => y.control === 'tree')
      .forEach(tree => tree.items.forEach(item => flatten(tree.name, item)))

    // helper function to get updated selection
    const getSelection = (agg, x, v) => {
      const item =
        agg.control === 'tree'
          ? flat[agg.name][v]
          : agg.items.find(a => a.key == v)
      const value = item ? item.value : v
      return {
        ...x,
        action: 'add',
        key: v,
        label: agg.label,
        value
      }
    }

    // replace initial selections with new objects that contain updated action, label, key and value
    state.selections
      .filter(x => x.action === 'init')
      .forEach(x => {
        const agg = data.aggregations.find(y => y.name === x.name)
        if (!agg) {
          return
        }
        if (agg.control === 'slider') {
          state.selections.push({
            ...x,
            action: 'add',
            label: agg.label
          })
        } else if (isArray(x.value)) {
          x.value.forEach(v => state.selections.push(getSelection(agg, x, v)))
        } else {
          state.selections.push(getSelection(agg, x, x.value))
        }
      })
    state.selections = state.selections.filter(x => x.action !== 'init')
    state.aggregations = data.aggregations
    state.pagination = data.pagination
    if (data.banners) {
      state.banners = data.banners
    }
    if (data.paging) {
      state.paging = data.paging
    }
    if (data.sorting) {
      state.sorting = data.sorting
    }
    if (data.grid) {
      state.gridItem = data.grid
    }
    if (data.list) {
      state.listItem = data.list
    }
    if (data.css) {
      state.css = data.css
    }
    if (data.filterLayout) {
      state.filterLayout = data.filterLayout
    }
    if (data.redirect) {
      state.redirect = data.redirect
    }
  },
  SET_LAYOUT(state, data) {
    state.layout = data
  },
  SET_SORT(state, data) {
    state.sort = data
  },
  SET_PAGE_SIZE(state, data) {
    state.pageSize = data
  },
  SET_PAGE(state, data) {
    state.page = data
  },
  SET_OVERLAY(state, data) {
    state.overlay = data
  },
  SET_KEYWORD(state, data) {
    state.keyword = data
  },
  SET_TOGGLE_LAYOUT(state, data) {
    state.toggleLayout = data
  },
  SET_PAGE_ID(state, data) {
    state.pageId = data
  },
  SET_COMPLETE(state, data) {
    state.complete = data
  },
  SET_CURRENT_SUGGESTION(state, data) {
    state.currentSuggestion = data
  },
  CLEAR_AUTOCOMPLETE(state) {
    state.complete = ''
    state.currentSuggestion = ''
    state.suggestItems = {}
    state.suggestResult = {}
  },
  SET_STATE(state, data) {
    state.page = data.page
    state.sort = data.sort
    state.pageSize = data.pageSize
    state.keyword = data.keyword
    state.filters = data.filters
    state.selections = data.selections
  },
  SET_QUERY_PARAM(state, data) {
    state.queryParam = data
  },
  SET_PAGE_PARAM(state, data) {
    state.pageParam = data
  },
  SET_CONTEXT(state, data) {
    state.context = data
  },
  SET_FALLBACK_MODE(state, data) {
    state.fallbackMode = data
  },
  UPDATE_AGGREGATION(state, agg) {
    const aggregation = state.aggregations.find(x => x.name === agg.name)
    if (aggregation) {
      aggregation.selected = agg.value
    }
  },
  UPDATE_SELECTIONS(state, last) {
    switch (last.action) {
      case 'remove-all':
        state.selections = state.selections.filter(x => x.name !== last.name)

        if (state.filters && state.filters[last.name]) {
          delete state.filters[last.name]
        }
        break

      case 'replace':
        state.selections = state.selections.filter(x => x.name !== last.name)
        state.selections.push(last)
        if (last.key == '_Keyword') {
          break
        }

        state.filters = state.filters || {}
        if (last.value && isArray(last.value)) {
          state.filters[last.name] = last.value
        } else {
          state.filters[last.name] = [last.key]
        }
        break

      case 'add':
        state.selections.push(last)
        if (last.key == '_Keyword') {
          break
        }

        state.filters = state.filters || {}
        state.filters[last.name] = state.filters[last.name] || []
        if (last.value && isArray(last.value)) {
          state.filters[last.name] = last.value
        } else {
          state.filters[last.name].push(last.key)
        }
        break

      default:
        state.selections = state.selections.filter(
          x => x.name !== last.name || x.key !== last.key
        )

        if (state.filters && state.filters[last.name]) {
          state.filters[last.name] = state.filters[last.name].filter(
            x => x !== last.key
          )
          if (state.filters[last.name].length === 0) {
            delete state.filters[last.name]
          }
        }
        break
    }
  },
  CLEAR_ONE_SELECTION(state, toClear) {
    state.selections = state.selections.filter(
      x => x.name !== toClear.name || x.key !== toClear.key
    )
    if (state.filters && state.filters[toClear.name]) {
      if (toClear.value && isArray(toClear.value)) {
        delete state.filters[toClear.name]
      } else {
        state.filters[toClear.name] = state.filters[toClear.name].filter(
          x => x !== toClear.key
        )
        if (state.filters[toClear.name].length === 0) {
          delete state.filters[toClear.name]
        }
      }
    }

    // special case for keyword selection
    if (toClear.key === '_Keyword') {
      state.keyword = ''
      // clear autocomplete
      state.complete = ''
      state.currentSuggestion = ''
      state.suggestItems = {}
      state.suggestResult = {}
    }

    const aggregation = state.aggregations.find(x => x.name === toClear.name)
    if (aggregation) {
      if (aggregation.control === 'slider') {
        aggregation.selected = []
      } else {
        aggregation.selected = aggregation.selected.filter(
          x => x !== toClear.key
        )
      }
    }
  },
  CLEAR_ALL_SELECTIONS(state, payload) {
    state.keyword = ''
    state.selections = []
    state.aggregations.forEach(agg => {
      agg.selected = []
    })
    state.filters = undefined
  },
  TRACK_EVENT(state, payload) {
    state.events.push(payload)
  },
  CLEAR_EVENTS(state) {
    state.events = []
  }
}

export const actions = {
  setLayout({ commit }, payload) {
    commit('SET_LAYOUT', payload)
  },
  setSort({ commit }, payload) {
    commit('SET_SORT', payload)
  },
  setPageSize({ commit }, payload) {
    commit('SET_PAGE_SIZE', payload)
  },
  setPage({ commit }, payload) {
    commit('SET_PAGE', payload)
  },
  setOverlay({ commit }, payload) {
    commit('SET_OVERLAY', payload)
  },
  setKeyword({ commit }, payload) {
    commit('SET_KEYWORD', payload)
  },
  setToggleLayout({ commit }, payload) {
    commit('SET_TOGGLE_LAYOUT', payload)
  },
  setComplete({ commit }, payload) {
    commit('SET_COMPLETE', payload)
  },
  setCurrentSuggestion({ commit }, payload) {
    commit('SET_CURRENT_SUGGESTION', payload)
  },
  clearAutocomplete({ commit }, payload) {
    commit('CLEAR_AUTOCOMPLETE', payload)
  },
  setPageId({ commit }, payload) {
    commit('SET_PAGE_ID', payload)
  },
  setState({ commit }, payload) {
    commit('SET_STATE', payload)
  },
  setQueryParam({ commit }, payload) {
    commit('SET_QUERY_PARAM', payload)
  },
  setPageParam({ commit }, payload) {
    commit('SET_PAGE_PARAM', payload)
  },
  setContext({ commit }, payload) {
    commit('SET_CONTEXT', payload)
  },
  updateAggregation({ commit }, payload) {
    commit('UPDATE_AGGREGATION', payload)
  },
  updateSelections({ commit }, payload) {
    commit('UPDATE_SELECTIONS', payload)
  },
  clearOneSelection({ commit }, payload) {
    commit('CLEAR_ONE_SELECTION', payload)
  },
  clearAllSelections({ commit }, payload) {
    commit('CLEAR_ALL_SELECTIONS', payload)
  },
  trackEvent({ commit }, payload) {
    commit('TRACK_EVENT', payload)
  },
  getEvents({ commit, state }) {
    const events = state.events
    commit('CLEAR_EVENTS')
    return events
  },
  async loadConfig({ commit }, payload) {
    try {
      const { data } = await this.$axios.get('/search/config')
      commit('LOAD_CONFIG', data)
    } catch {
      commit('SET_FALLBACK_MODE', true)
    }
  },
  async runAutocomplete({ commit }, payload) {
    const { data } = await this.$axios.post('/search/autocomplete/', payload)

    commit('RUN_AUTOCOMPLETE', {
      includeSuggestResult: payload.autocompleteConfig.includeSuggestResult,
      primaryKey: data.searchResult.primaryKey,
      data: data
    })
  },
  async runQuery({ commit, state }, payload) {
    commit('SET_PAGE_ID', payload.query.pageId || 0)

    try {
      const res = await this.$axios.post('/search/query', payload)

      // set default pagination
      for (const paging of res.data.paging) {
        if (paging.default && !state.pageSize) {
          commit('SET_PAGE_SIZE', paging.value)
          break
        }
      }
      // set default sorting
      for (const sorting of res.data.sorting) {
        if (sorting.default && !state.sort) {
          commit('SET_SORT', sorting.key)
          break
        }
      }
      const skip = (payload.query.page - 1) * state.pageSize
      const total = res.data.total || 0
      const pagination = {
        pagingType: res.data.pagingType || 'standard',
        current_page: payload.query.page,
        per_page: state.pageSize,
        total: total,
        from: skip + 1,
        to: skip + state.pageSize,
        last_page: Math.ceil(total / state.pageSize)
      }
      const data = {
        hits: res.data,
        primaryKey: res.data.primaryKey,
        queryId: res.data.queryId,
        segments: res.data.segments,
        pagination: pagination,
        aggregations: res.data.aggregations,
        banners: res.data.banners,
        paging: res.data.paging,
        sorting: res.data.sorting,
        grid: res.data.grid,
        list: res.data.list,
        css: res.data.css,
        filterLayout: res.data.filterLayout,
        redirect: res.data.redirect
      }
      commit('RUN_QUERY', data)
    } catch {
      commit('SET_FALLBACK_MODE', true)
    }
  }
}

export const getters = {
  getFacetBanners: state => {
    const banners = { ...state.banners }
    for (const banner in banners) {
      if (!banner.startsWith('facet')) {
        delete banners[banner]
      }
      if (isEmpty(banners[banner])) {
        delete banners[banner]
      }
    }
    return banners
  },
  getBannerByZone: state => zone => {
    return state.banners[zone]
  },
  getQuery: state => () => {
    return {
      page: state.page,
      sort: state.sort,
      pageSize: state.pageSize,
      keyword: state.keyword,
      filters: state.filters
    }
  }
}

export const search = {
  namespaced,
  state,
  getters,
  mutations,
  actions
}
