import Vue from 'vue'
import axios from 'axios'
import app from '../main' // import the instance
import { paramCase, camelCase, snakeCase } from 'change-case'
import pluralize from 'pluralize'
import checkResponse from '@/utils/checkResponse'
import parserFilters from '@/utils/parserFilters'
import parserSlug from '@/utils/parserSlug'

export default class {
  constructor (module, model, detail = null) {
    let camelCaseModel = camelCase(module)
    let snakeCaseModel = snakeCase(module)
    let camelCaseModelSingular = pluralize.singular(camelCaseModel)
    let paramCaseModel = paramCase(module)
    this.state = {
      pagination: {
        currentPage: 1,
        perPage: 5,
        totalUsers: 0,
        totalPages: 0
      },
      catalog: {},
      filterParams: '',
      isModalVisible: false
    }

    this.mutations = {
      SET_RECORD (state, payload) {
        state[camelCaseModelSingular] = payload
      },
      SET_RECORDS (state, payload) {
        state[camelCaseModel] = payload.data

        state.pagination = {
          currentPage: payload.current_page,
          perPage: payload.per_page,
          totalUsers: payload.total,
          totalPages: payload.last_page
        }
      },
      ADD_RECORD (state, payload) {
        state[camelCaseModel].unshift(payload)
      },
      UPDATE_RECORD (state, payload) {
        const idx = state[camelCaseModel].findIndex(u => u.id === payload.id)
        if (idx >= 0) {
          Vue.set(state[camelCaseModel], idx, payload)
        }
      },
      DELETE_RECORD (state, payload) {
        const idx = state[camelCaseModel].findIndex(u => u.id === payload.id)

        if (idx >= 0) {
          Vue.delete(state[camelCaseModel], idx)
        }
      },
      DELETE_RECORDS (state, payload) {
        for (let id of payload.ids) {
          const idx = state[camelCaseModel].findIndex(u => u.id === id)

          if (idx >= 0) {
            Vue.delete(state[camelCaseModel], idx)
          }
        }
      },
      ADD_RECORD_DETAIL (state, payload) {
        state[camelCaseModelSingular].details.unshift(payload)
      },
      UPDATE_RECORD_DETAIL (state, { payload, idx }) {
        if (idx >= 0) {
          Vue.set(state[camelCaseModelSingular].details, idx, payload)
        }
      },
      DELETE_RECORD_DETAIL (state, idx) {
        if (idx >= 0) {
          Vue.delete(state[camelCaseModelSingular].details, idx)
        }
      },
      DELETE_RECORD_DETAILS (state, payload) {
        for (let idx of payload.indexes) {
          if (idx >= 0) {
            Vue.delete(state[camelCaseModelSingular].details, idx)
          }
        }
      },
      SET_MODAL_VISIBLE (state, payload) {
        state.isModalVisible = payload
      },
      SET_FILTER_PARAMS (state, payload) {
        state.filterParams = payload
      },
      SET_CATALOG (state, { object, payload }) {
        Vue.set(state.catalog, object, payload.data)
      }
    }

    this.actions = {
      async loadRecord ({ commit }, payload) {
        app.$Progress.start()
        try {
          const response = await axios.get(`${paramCaseModel}/${payload.id}`)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('SET_RECORD', response.data)
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      async loadRecords ({ commit }, payload) {
        app.$Progress.start()
        try {
          const response = await axios.get(`${paramCaseModel}?page=${payload.page}${this.getters[module + '/filterParams']}`)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('SET_RECORDS', response.data)
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      async addRecord ({ commit }, payload) {
        const record = model(payload)

        app.$Progress.start()

        try {
          const response = await axios.post(paramCaseModel, record)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('ADD_RECORD', response.data)
            commit('SET_MODAL_VISIBLE', false)
            commit('SET_ACCEPT_ALERT', { color: 'success', title: 'strings.' + snakeCaseModel, text: 'front.added_successfully', icon: 'checkmark-circle-outline' }, { root: true })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      async editRecord ({ commit }, payload) {
        const record = model(payload)

        app.$Progress.start()

        try {
          const response = await axios.put(`${paramCaseModel}/${payload.id}`, record)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('UPDATE_RECORD', response.data)
            commit('SET_MODAL_VISIBLE', false)
            commit('SET_ACCEPT_ALERT', { color: 'success', title: 'strings.' + snakeCaseModel, text: 'front.updated_successfully', icon: 'checkmark-circle-outline' }, { root: true })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      updateRecord ({ commit }, payload) {
        const record = model(payload)
        commit('UPDATE_RECORD', record)
      },
      async deleteRecord ({ commit }, payload) {
        app.$Progress.start()
        try {
          const response = await axios.delete(`${paramCaseModel}/${payload.id}`)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('DELETE_RECORD', payload)
            commit('SET_MODAL_VISIBLE', false)
            commit('SET_ACCEPT_ALERT', { color: 'success', title: 'strings.' + snakeCaseModel, text: 'front.deleted_successfully', icon: 'checkmark-circle-outline' }, { root: true })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      async deleteRecords ({ commit }, payload) {
        app.$Progress.start()
        try {
          const response = await axios.delete(`${paramCaseModel}/delete`, { params: { ids: payload.ids } })
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('DELETE_RECORDS', payload)
            commit('SET_ACCEPT_ALERT', { color: 'success', title: 'strings.' + snakeCaseModel, text: 'front.deleted_successfully', icon: 'checkmark-circle-outline' }, { root: true })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      async addRecordDetail ({ commit }, payload) {
        app.$Progress.start()
        const record = detail(payload)
        commit('ADD_RECORD_DETAIL', record)
        commit('SET_MODAL_VISIBLE', false)
      },
      async editRecordDetail ({ commit }, payload) {
        app.$Progress.start()
        const record = detail(payload)
        commit('UPDATE_RECORD_DETAIL', { payload: record, idx: payload.index })
        commit('SET_MODAL_VISIBLE', false)
        app.$Progress.finish()
      },
      async deleteRecordDetail ({ commit }, payload) {
        app.$Progress.start()
        commit('DELETE_RECORD_DETAIL', payload.index)
        app.$Progress.finish()
      },
      async deleteRecordDetails ({ commit }, payload) {
        app.$Progress.start()
        commit('DELETE_RECORD_DETAILS', payload)
        app.$Progress.finish()
      },
      async actionRecord ({ commit }, payload) {
        app.$Progress.start()
        try {
          const response = await axios.put(`${paramCaseModel}/${payload.id}/${payload.action}`)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('SET_RECORD', response.data)
            commit('UPDATE_RECORD', response.data)
            commit('SET_ACCEPT_ALERT', { color: 'success', title: 'strings.' + snakeCaseModel, text: `${module}.${payload.action}`, icon: 'checkmark-circle-outline' }, { root: true })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      setModalImportVisible ({ commit }) {
        commit('SET_MODAL_IMPORT_VISIBLE', true, { root: true })
      },
      exportRecords ({ commit }) {
        app.$Progress.start()
        try {
          window.open(`${axios.defaults.baseURL}/${paramCaseModel}/export?format=csv${this.getters[module + '/filterParams']}`)
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      printReportRecord ({ commit }, payload) {
        app.$Progress.start()
        try {
          window.open(`${axios.defaults.baseURL}/${paramCaseModel}/${payload.id}/export`)
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      applyFilter ({ commit }, payload) {
        const filter = parserFilters(payload)
        commit('SET_FILTER_PARAMS', filter)
      },
      clearFilter ({ commit }, payload) {
        const filter = ''
        commit('SET_FILTER_PARAMS', filter)
      },
      async loadCatalog ({ commit }, payload) {
        let url = parserSlug(payload.url)
        app.$Progress.start()
        try {
          const response = await axios.get(`${url}${payload.filter}`)
          const checkErrors = checkResponse(response)

          if (checkErrors) {
            app.$Progress.fail()
            commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: checkErrors.message }, { root: true })
          } else {
            commit('SET_CATALOG', { object: payload.url, payload: response.data })
          }
        } catch (e) {
          app.$Progress.fail()
          commit('SET_ALERT_MESSAGE', { color: 'danger', title: 'errors.connection_error', text: 'errors.generic_error' }, { root: true })
        } finally {
          app.$Progress.finish()
        }
      },
      loadCatalogAux ({ commit }, payload) {
        commit('SET_CATALOG', { object: payload.url, payload: payload })
      },
      setModalVisible ({ commit }, payload) {
        commit('SET_MODAL_VISIBLE', payload)
      }
    }

    this.getters = {
      catalog: state => state.catalog,
      pagination: state => state.pagination,
      isModalVisible: state => state.isModalVisible,
      filterParams: state => state.filterParams
    }
  }
}
