import _ from 'lodash'
import { mapState, mapActions, mapGetters } from 'vuex'

export default {
  computed: {
    ...mapState({
      masterData: state => state.masterDataModule.master_data,
      countriesOptions: state => state.locationModule.allCountries,
      fields: state => state.locationModule.dynamicContentData.data,
      statesOptions: state => state.locationModule.statesByCountriesData.data,
      citiesOptions: state => state.locationModule.citiesByStateData.data,
      userSelectedAddress: state => state.locationModule.dynamicContentData.data.address,
    }),
    ...mapGetters(['isLoading']),
    /**
     * Get Address String
     *
     * Creates address string for the given address
     *
     * @param vue
     */
    getAddressString: vue => (address, html = false, titleOnly = false) => {
      if (titleOnly) {
        if (address !== undefined && Object.keys(address).length > 0) {
          return address.title
        } else {
          return ''
        }
      }
      let divider = ', '
      if (html) {
        divider = ', </br>'
      }
      let countriesOptions = vue.countriesOptions
      let statesOptions = vue.statesOptions
      let citiesOptions = vue.citiesOptions
      if (Object.keys(address).length > 0 && countriesOptions.length > 0) {
        // Country Data
        let countryField = address.fields.find(x => x.key === 'countries')
        let country = false
        let state = false
        let city = false
        if (countryField) {
          country = countriesOptions.find(x => x.id === countryField.value)
        }
        // State Data
        if (statesOptions.options.length > 0) {
          let stateField = address.fields.find(x => x.key === 'states')
          if (stateField) {
            state = statesOptions.options.find(x => x.value === stateField.value)
          }
        }
        // Cities Data
        if (citiesOptions.options.length > 0) {
          let cityField = address.fields.find(x => x.key === 'cities')
          if (cityField) {
            city = citiesOptions.options.find(x => x.value === cityField.value)
          }
        }
        return vue
          .removeLastComma(
            vue
              .sortDynamicFields(address.fields)
              .reduce((addressString, field) => {
                if (field.value !== null && field.value !== '') {
                  if (field.key === 'countries' && country) {
                    addressString.push(country.name)
                  } else if (field.key === 'states' && state) {
                    addressString.push(state.text)
                  } else if (field.key === 'cities' && city) {
                    addressString.push(city.text)
                  } else {
                    addressString.push(field.value)
                  }
                }
                return addressString
              }, [])
              .filter(item => {
                return (typeof item === 'string' && item.trim().length > 0) || true
              })
              .join(', ')
          )
          .trim()
          .replace(/,/g, divider) // replace divider globally
      } else {
        return ''
      }
    },
    /**
     * Get field Options Data
     *
     * @param index The address index
     * @param field The field to process
     *
     * @returns []
     */
    getFieldOptionsData: vue => (index, field, filterOptions = {}) => {
      let name = field.key + 'Options'
      if (typeof vue[name] !== 'undefined') {
        if (field.key === 'countries') {
          let countries = vue[name].map(country => {
            return {
              value: country.id,
              text: vue.$helpers.getValue(country, 'translated_name.content', country.name),
              active: country.active,
            }
          })

          if (
            !vue.$helpers.isSet(filterOptions, 'countriesFilter') &&
            vue.$helpers
              .getValue(vue.addresses[index], 'title', '')
              .toLowerCase()
              .includes('shipping')
          ) {
            countries = countries.filter(country => {
              return country.active === 1
            })
          }

          return vue.$helpers.isSet(filterOptions, 'countriesFilter')
            ? countries.filter(x => filterOptions.countriesFilter.includes(x.value))
            : countries
        }
        if (field.key === 'states') {
          let country = vue.addresses[index].fields.find(x => x.key === 'countries')
          let states = vue[name].options.filter(item => item.country_id === country.value)
          return states
        }
        if (field.key === 'cities') {
          let stateFieldIndex = vue.addresses[index].fields.find(x => x.key === 'states')
          if (stateFieldIndex && (stateFieldIndex.value !== '-1' || stateFieldIndex.value !== null)) {
            let cities = vue[name].options.filter(item => item.state_id === stateFieldIndex.value)
            if (cities.length < 1) {
              vue.setCities(stateFieldIndex.value)
              if (!vue.citiesRequested.includes(stateFieldIndex.value)) {
                vue.citiesRequested.push(stateFieldIndex.value)
              }
              cities = vue[name].options.filter(item => item.state_id === stateFieldIndex.value)
            }
            return cities
          }
        }
        return this[name]
      } else {
        if (typeof field.options !== 'undefined') {
          return field.options
        } else {
          return []
        }
      }
    },
    isFieldLoading: vue => field => {
      if (typeof field.key === undefined) {
        return false
      } else if (field.key === 'countries') {
        return vue.isLoading('locationsLoadAllCountries')
      } else if (field.key === 'states') {
        return vue.isLoading('locationStateLoading')
      } else if (field.key === 'cities') {
        return vue.isLoading('locationStateCitiesLoading')
      } else {
        return vue.loadingAddresses
      }
    },
  },
  data: () => ({
    selectedAddress: '',
    selectedCountry: '',
    selectedCountryByIndex: [],
    // Enable or disable preload states and city on load
    enableMixinInitCheck: true,
    addresses: [],
    requestedStates: [],
    citiesRequested: [],
    master: { keys: [] },
    addressMixinInitialized: false,
    loadingAddresses: false,
    initializeAddressPromise: null,
    initializeAddressPromiseResolver: () => {},
    currentSelectedCountryId: null,
  }),
  watch: {
    master: {
      handler() {
        this.loadMasterDataKeys({
          country_id: this.master.country_id,
          keys: this.master.keys,
        })
      },
      deep: true,
    },
  },
  mounted() {
    this.initMixin(this.enableMixinInitCheck)
    this.initializeAddressPromise = new Promise(resolve => {
      this.initializeAddressPromiseResolver = resolve
    })
  },
  methods: {
    ...mapActions([
      'getDynamicContent',
      'loadStatesByCountry',
      'loadCitiesByState',
      'loadMasterDataKeys',
      'loadAllCountries',
    ]),
    masterDataConfigOptionsCreator(key) {
      if (typeof this.masterData[key] !== 'undefined') {
        return this.masterData[key].map(opt => ({ config: opt.title }))
      }
      return []
    },
    /**
     * Initialize mixin with preload state & cities by passing status = true
     * @param status true to initialize status
     * @param reset false if the requested states and cities need to be reseted
     */
    initMixin(status, reset = true) {
      let statesRequested = reset ? [] : this.requestedStates
      let citiesRequested = reset ? [] : this.citiesRequested
      let promisses = []
      if (this.countriesOptions.length === 0 && !this.isLoading('locationsLoadAllCountries')) {
        promisses.push(this.loadAllCountries())
      }

      if (this.addresses.length > 0 && status) {
        this.loadingAddresses = true
        this.addresses.forEach(obj => {
          Object.entries(obj).forEach(entry => {
            const [key, value] = entry
            if (key === 'fields' && typeof value !== 'undefined') {
              value.forEach(item => {
                if (item.key === 'countries') {
                  if (!statesRequested.includes(item.value)) {
                    if (item.value !== '' && item.value !== null) {
                      statesRequested.push(item.value)
                      promisses.push(this.setStates(item.value))
                    }
                  }
                }
                if (item.key === 'states') {
                  if (!citiesRequested.includes(item.value)) {
                    if (item.value !== '' && item.value !== null) {
                      citiesRequested.push(item.value)
                      promisses.push(this.setCities(item.value))
                    }
                  }
                }
              })
            }
          })
        })
        if (promisses.filter(promis => promis !== undefined && typeof promis.then === 'function').length > 0) {
          Promise.all(promisses).then(() => {
            this.$nextTick(() => {
              this.addressMixinInitialized = true
              this.loadingAddresses = false
              this.initializeAddressPromiseResolver()
            })
          })
        } else {
          // Nothing to resolve
          this.loadingAddresses = false
          this.addressMixinInitialized = true
        }
      }
      this.requestedStates = statesRequested
      this.citiesRequested = citiesRequested
    },
    /**
     * An address is considered unfilled when the filled length is zero
     *
     * @return {int} index of the next unfilled address
     */
    getNexUnfilledAddressIndex() {
      return this.addresses.findIndex(address => {
        if (address.fields.length === 0) {
          return true
        }
      })
    },
    /**
     * get Filled Addresses
     *
     * returns addresses which has filled and valid data as per requirement
     *
     * @param sorted
     */
    getFilledAddresses(sorted = true) {
      let addresses = this.addresses.filter(address => {
        let countryField = address.fields.find(x => x.key === 'countries')
        let unfilledRequired = address.fields.filter(x => {
          return (
            x.required === true &&
            (x.value === '' || x.value === null || (typeof x.value === 'string' && x.value.trim() === ''))
          )
        })
        return (
          typeof countryField !== 'undefined' &&
          countryField.value !== '' &&
          countryField.value !== null &&
          unfilledRequired.length === 0
        )
      })
      if (sorted) {
        addresses = addresses.map(address => {
          if (address.fields.length > 0) {
            address.fields = this.sortDynamicFields(address.fields)
          }
          return address
        })
      }
      return addresses
    },
    /**
     * Trigger form field change
     *
     * @param {object} field the field of the address field list
     * @param {boolean} initialize to reinitialize current selected address
     */
    formFieldChanged(field, value, initialize = true) {
      if (field.key === 'countries') {
        this.loadDynamicAddress(value, this.selectedAddress, initialize, this.selectedAddress)
      }
    },
    /**
     * Loads a dynamic address
     *
     * @param {int} countryId country id to use when loading dynamic data
     * @param {boolean} selectedIndex the index to load the data to, if not given an index will be appended
     * @param {boolean} initialize if to initialize data
     * @param {?int} cloneDataFromIndex the index to clone data from
     */
    loadDynamicAddress(countryId, selectedIndex = false, initialize = true, cloneDataFromIndex = null) {
      let addresses = this.addresses
      let previousAddressCopy = cloneDataFromIndex ? _.cloneDeep(this.addresses[this.selectedAddress]) : { fields: [] }
      let customAddressIndex = addresses.findIndex(address => address.title === 'Custom Address')
      let customAddressCountryId = countryId
      this.currentSelectedCountryId = countryId
      if (selectedIndex === false) {
        if (customAddressIndex === -1) {
          selectedIndex = addresses.length
          addresses.push({
            title: 'Custom Address',
            fields: this.customAddressFields || [],
            custom: true,
          })
        } else {
          selectedIndex = customAddressIndex
          customAddressCountryId = (country => (country ? country.value : customAddressCountryId))(
            this.addresses[customAddressIndex].fields.find(field => field.key === 'countries')
          )
        }
        this.selectedAddress = selectedIndex
      }

      // if custom address is not already loaded
      if (
        selectedIndex ||
        customAddressIndex === -1 ||
        (customAddressCountryId !== countryId && this.isAllowedAllCountries !== true)
      ) {
        let query = {
          country_id: countryId,
          types: ['address'],
        }
        this.getDynamicContent(query).then(() => {
          if (this.userSelectedAddress !== undefined && this.userSelectedAddress.length > 0) {
            try {
              let userSelectedAddress = JSON.parse(this.userSelectedAddress)
              if (this.$helpers.isSet(userSelectedAddress, '[0].fields')) {
                addresses[this.selectedAddress].fields = userSelectedAddress[0].fields.map(field => {
                  if (field.key === 'countries') {
                    field.value = countryId
                  } else {
                    let previousField = previousAddressCopy.fields.find(pfield => {
                      return pfield.index === field.index && pfield.type === field.type
                    })
                    if (previousField) {
                      field.value = previousField.value
                    }
                  }
                  return field
                })
                // unset state
                let stateFieldIndex = addresses[this.selectedAddress].fields.findIndex(field => field.key === 'states')
                if (stateFieldIndex !== -1) {
                  addresses[this.selectedAddress].fields[stateFieldIndex].value = null
                }
                // unset city
                let cityFieldIndex = addresses[this.selectedAddress].fields.findIndex(field => field.key === 'cities')
                if (cityFieldIndex !== -1) {
                  addresses[this.selectedAddress].fields[cityFieldIndex].value = null
                }

                this.selectedCountry = countryId
                if (initialize) {
                  this.initMixin(true, false)
                }
              }
            } catch (e) {
              // TODO: log this to error log
            }
          }
        })
      } else {
        this.selectedCountry = customAddressCountryId
        if (initialize) {
          this.initMixin(true, false)
        }
      }
    },
    /**
     * Get state name for a given state
     * @param stateId
     */
    getStateName(stateId) {
      let stateOption = this.statesOptions.options.find(x => x.value === stateId)
      return stateOption ? stateOption.text : ''
    },
    /**
     * Get city name for a given city
     * @param {int} cityId
     */
    getCityName(cityId) {
      let citiesOption = this.citiesOptions.options.find(x => x.value === cityId)
      return citiesOption ? citiesOption.text : ''
    },
    /**
     * Set user selected address based user available address pass address index
     * @param index
     */
    setSelectedAddress(index) {
      this.selectedAddress = index
      this.selectedCountry = ''
    },
    /**
     * Get selected address index
     *
     * @param index
     */
    getSelectedAddressIndex() {
      return this.selectedAddress
    },
    /**
     * Sort field array based on order
     * @param fields
     * @returns {*}
     */
    sortDynamicFields(fields) {
      return _.orderBy(fields, 'order', 'asc')
    },
    /**
     * Sort field array based on order reverse
     * @param fields
     * @returns {*}
     */
    sortDynamicFieldsReverse(fields) {
      return _.orderBy(fields, 'order', 'desc')
    },
    /**
     * Sort field array with country state and city on top
     * @param fields
     * @returns {*}
     */
    sortDynamicFieldsCountryStateCityTop(fields) {
      let keyOrder = ['countries', 'states', 'cities']
      let keyLabelOrder = ['country', 'state', 'city']
      return _.chain(fields)
        .orderBy('order', 'asc')
        .sortBy(item => (keyOrder.indexOf(item.key) !== -1 ? keyOrder.indexOf(item.key) : keyOrder.length))
        .sortBy(item =>
          keyLabelOrder.indexOf(item.label.toLowerCase()) !== -1
            ? keyLabelOrder.indexOf(item.label.toLowerCase())
            : keyOrder.length
        )
        .value()
    },
    /**
     * Return back current index after sorting based on order to make sure inline with original array
     * @param fields
     * @param index
     */
    setDynamicFieldIndex(fields, index) {
      return fields.findIndex(x => x.index === index)
    },
    /**
     * Set select options dynamically
     * @param key
     * @param identifier
     * @param index1
     * @param index2
     * @returns {*}
     */
    setDynamicFieldKeyOptionsData(key, identifier, index1, index2) {
      let name = key + 'Options'
      if (typeof this[name] !== 'undefined') {
        if (key === 'states') {
          let country = this.addresses[index1].fields.find(x => x.key === 'countries')
          let states = this[name].options.filter(item => item.country_id === country.value)
          return states
        }
        if (key === 'cities') {
          let stateFieldIndex = this.addresses[index1].fields.findIndex(x => x.key === 'states')
          let cities = this[name].options.filter(
            item => item.state_id === this.addresses[index1].fields[stateFieldIndex].value
          )
          return cities
        }
        return this[name]
      } else {
        return []
      }
    },
    setAddressFormat() {
      if (this.addresses[this.selectedAddress].fields.length < 1) {
        let query = {
          country_id: this.getSelectedAddressCountryId(),
          types: ['address'],
        }
        let self = this
        this.getDynamicContent(query).then(res => {
          if (typeof self.fields.address !== 'undefined' && self.fields.address.length > 0) {
            JSON.parse(self.fields.address).forEach(items => {
              items.fields.forEach(field => {
                if (field.type === 'select') {
                  self.setSelectDataValue(field.value, field.type)
                }
                if (field.key === 'countries') {
                  field.value = this.selectedCountry
                  self.setStates(self.selectedCountry)
                }
                self.addresses[self.selectedAddress].fields.push(field)
              })
            })
          }
        })
      } else {
        this.addresses.forEach(items => {
          items.fields.forEach(field => {
            if (field.type === 'select') {
              this.setSelectDataValue(field.value, field.type)
            }
            if (field.key === 'countries') {
              field.value = this.selectedCountry
              this.setStates(this.selectedCountry)
            }
          })
        })
      }
    },
    setSelectDataValue(id, key, type) {
      let name = key + 'Options'
      if (typeof this[name] !== 'undefined') {
        if (typeof this[name].options !== 'undefined') {
          let value = this[name].options.find(x => x.value === id)
          if (typeof value !== 'undefined') {
            return value.label
          }
        }
      }
      return ''
    },
    setCountrySelectionOnSelectedAddress(force = false) {
      let selectedIndex = this.selectedCountryByIndex.findIndex(item => item.index === this.selectedAddress)
      if (selectedIndex !== -1) {
        this.selectedCountryByIndex.pop(selectedIndex)
      }
      this.selectedCountryByIndex.push({ index: this.selectedAddress, country_id: this.selectedCountry })
      this.setAddressFormat()
    },
    getSelectedAddressCountryId() {
      if (typeof this.selectedAddress !== 'undefined') {
        return (country => (country ? country.value : null))(
          this.$helpers
            .getValue(this.addresses[this.selectedAddress], 'fields', [])
            .find(item => item.key === 'countries')
        )
      }
      return null
    },
    setStates(id) {
      if (id !== undefined && id !== null) {
        if (!this.isLoading('locationStateLoading-' + id)) {
          let query = {
            country_id: id,
            relations: ['states'],
          }
          return this.loadStatesByCountry(query)
        }
        return Promise.resolve()
      }
    },
    /**
     *
     * @param id = state_id
     */
    setCities(id) {
      if (id !== undefined && id !== null && id !== '') {
        if (!this.isLoading('locationStateCitiesLoading-' + id)) {
          let query = {
            state_id: id,
          }
          return this.loadCitiesByState(query)
        }
        return Promise.resolve()
      }
    },
    setAddressFields(copyFrom, copyTo) {
      let copyFromData = this.addresses[copyFrom].fields
      if (copyFromData.length > 0) {
        this.addresses[copyTo].fields = JSON.parse(JSON.stringify(copyFromData))
      }
    },
    removeLastComma(str) {
      return str.replace(/,(\s+)?$/, '')
    },
    /**
     * Clear the selected addres fields
     */
    clearSelectedAddress() {
      let length = this.addresses[this.selectedAddress].fields.length
      for (let i = 0; i < length; i++) {
        this.addresses[this.selectedAddress].fields[i].value = ''
      }
    },
    /**
     * Find the Country id for a given address
     */
    findAddressCountryId(address) {
      let countryField = this.$helpers.getValue(address, 'fields', []).find(field => field.key === 'countries')
      if (countryField) {
        return countryField.value
      } else {
        return false
      }
    },
  },
}
