<template>
  <Modal @hidden="hidden">
    <div v-if="loadingViews" class="loading-overlay"></div>
    <h2 class="box__title">
      {{ $t('exportTableModal.title', { name: table.name }) }}
    </h2>
    <Error :error="error"></Error>
    <ExportTableForm
      ref="form"
      v-slot="{ filename }"
      :database="database"
      :table="table"
      :view="view"
      :views="views"
      :loading="loading"
      :enable-views-dropdown="enableViewsDropdown"
      @submitted="submitted"
      @values-changed="valuesChanged"
    >
      <ExportLoadingBar
        :job="job"
        :loading="loading"
        :disabled="!isValid"
        :filename="filename"
      >
      </ExportLoadingBar>
    </ExportTableForm>
  </Modal>
</template>

<script>
import { mapState } from 'vuex'

import modal from '@baserow/modules/core/mixins/modal'
import error from '@baserow/modules/core/mixins/error'
import ExporterService from '@baserow/modules/database/services/export'
import ViewService from '@baserow/modules/database/services/view'
import { populateView } from '@baserow/modules/database/store/view'
import ExportTableForm from '@baserow/modules/database/components/export/ExportTableForm'
import ExportLoadingBar from '@baserow/modules/database/components/export/ExportLoadingBar'

export default {
  name: 'ExportTableModal',
  components: { ExportTableForm, ExportLoadingBar },
  mixins: [modal, error],
  props: {
    database: {
      type: Object,
      required: true,
    },
    table: {
      type: Object,
      required: true,
    },
    view: {
      type: Object,
      required: false,
      default: null,
    },
    startExport: {
      type: Function,
      required: false,
      default: function ({ table, values, client }) {
        return ExporterService(client).export(table.id, values)
      },
    },
    getJob: {
      type: Function,
      required: false,
      default: function (job, client) {
        return ExporterService(client).get(job.id)
      },
    },
    enableViewsDropdown: {
      type: Boolean,
      required: false,
      default: true,
    },
  },
  data() {
    return {
      views: [],
      loadingViews: false,
      loading: false,
      job: null,
      pollInterval: null,
      isValid: false,
    }
  },
  computed: {
    jobHasFailed() {
      return ['failed', 'cancelled'].includes(this.job.state)
    },
    jobIsRunning() {
      return (
        this.job !== null && this.job.state !== 'finished' && !this.jobHasFailed
      )
    },
    ...mapState({
      selectedTableViews: (state) => state.view.items,
    }),
  },
  methods: {
    async show(...args) {
      const show = modal.methods.show.call(this, ...args)
      this.job = null
      this.loading = false
      await this.fetchViews()
      this.$nextTick(() => {
        this.valuesChanged()
      })
      return show
    },
    hidden(...args) {
      this.stopPollIfRunning()
    },
    async fetchViews() {
      if (this.table._.selected) {
        this.views = this.selectedTableViews
        return
      }

      this.loadingViews = true
      try {
        const { data: viewsData } = await ViewService(this.$client).fetchAll(
          this.table.id
        )
        viewsData.forEach((v) => populateView(v, this.$registry))
        this.views = viewsData
      } catch (error) {
        this.handleError(error, 'views')
      }
      this.loadingViews = false
    },
    async submitted(values) {
      if (!this.$refs.form.isFormValid()) {
        return
      }

      this.loading = true
      this.hideError()

      try {
        const { data } = await this.startExport({
          table: this.table,
          view: this.view,
          values,
          client: this.$client,
        })
        this.job = data
        if (this.pollInterval !== null) {
          clearInterval(this.pollInterval)
        }
        this.pollInterval = setInterval(this.getLatestJobInfo, 1000)
      } catch (error) {
        this.stopPollAndHandleError(error)
      }
    },
    async getLatestJobInfo() {
      try {
        const { data } = await this.getJob(this.job, this.$client)
        this.job = data
        if (!this.jobIsRunning) {
          this.loading = false
          this.stopPollIfRunning()
        }
        if (this.jobHasFailed) {
          const title =
            this.job.state === 'failed'
              ? this.$t('exportTableModal.failedTitle')
              : this.$t('exportTableModal.cancelledTitle')
          const message =
            this.job.state === 'failed'
              ? this.$t('exportTableModal.failedDescription')
              : this.$t('exportTableModal.cancelledDescription')
          this.showError(title, message)
        }
      } catch (error) {
        this.stopPollAndHandleError(error)
      }
    },
    stopPollAndHandleError(error) {
      this.loading = false
      this.stopPollIfRunning()
      this.handleError(error, 'export')
    },
    stopPollIfRunning() {
      if (this.pollInterval) {
        clearInterval(this.pollInterval)
      }
    },
    valuesChanged() {
      this.isValid = this.$refs.form.isFormValid()
      this.job = null
    },
  },
}
</script>