import { mapActions, mapGetters } from 'vuex'
import { DataProviderType } from '@baserow/modules/core/dataProviderTypes'
import { notifyIf } from '@baserow/modules/core/utils/error'
import _ from 'lodash'

export default {
  data() {
    return {
      // The first page has been loaded by the data provider at page load already
      currentOffset: this.element.items_per_page,
      errorNotified: false,
      resetTimeout: null,
    }
  },
  computed: {
    ...mapGetters({
      getLoading: 'elementContent/getLoading',
      getHasMorePage: 'elementContent/getHasMorePage',
      getElementContent: 'elementContent/getElementContent',
      getReset: 'elementContent/getReset',
      getPageDataSourceById: 'dataSource/getPageDataSourceById',
    }),
    reset() {
      return this.getReset(this.element)
    },
    dataSource() {
      if (!this.element.data_source_id) {
        return null
      }
      return this.getPageDataSourceById(this.page, this.element.data_source_id)
    },
    elementContent() {
      if (
        !this.element.data_source_id ||
        !this.getElementContent(this.element)
      ) {
        return []
      }

      return this.getElementContent(this.element)
    },
    hasMorePage() {
      return this.getHasMorePage(this.element)
    },
    contentLoading() {
      return this.getLoading(this.element)
    },
    dispatchContext() {
      return DataProviderType.getAllDataSourceDispatchContext(
        this.$registry.getAll('builderDataProvider'),
        this.applicationContext
      )
    },
  },
  watch: {
    reset() {
      this.debouncedReset()
    },
    'element.data_source_id'() {
      this.debouncedReset()
    },
    'element.items_per_page'() {
      this.debouncedReset()
    },
    dispatchContext: {
      handler(newValue, prevValue) {
        if (!_.isEqual(newValue, prevValue)) {
          this.debouncedReset()
        }
      },
      deep: true,
      immediate: true,
    },
  },
  async mounted() {
    if (this.element.data_source_id) {
      await this.fetchContent([0, this.element.items_per_page])
    }
  },
  methods: {
    ...mapActions({
      fetchElementContent: 'elementContent/fetchElementContent',
      clearElementContent: 'elementContent/clearElementContent',
    }),
    debouncedReset() {
      clearTimeout(this.resetTimeout)
      this.resetTimeout = setTimeout(() => {
        this.errorNotified = false
        this.currentOffset = 0
        this.loadMore(true)
      }, 500)
    },
    async fetchContent(range, replace) {
      try {
        await this.fetchElementContent({
          element: this.element,
          dataSource: this.dataSource,
          data: this.dispatchContext,
          range,
          replace,
        })
        this.currentOffset += this.element.items_per_page
      } catch (error) {
        // We need to only launch one toast error message per element,
        // not one per element fetch, or we can end up with many error
        // toasts per element sharing a datasource.
        if (!this.errorNotified) {
          this.errorNotified = true
          notifyIf(error)
        }
      }
    },
    async loadMore(replace = false) {
      await this.fetchContent(
        [this.currentOffset, this.element.items_per_page],
        replace
      )
    },
  },
}