<template>
  <Context
    class="data-source-context"
    :class="{ 'context--loading-overlay': state === 'loading' }"
    :overflow-scroll="true"
    :max-height-if-outside-viewport="true"
    @shown="shown"
  >
    <template v-if="state === 'loaded'">
      <div v-if="dataSources.length > 0">
        <DataSourceForm
          v-for="dataSource in dataSources"
          :id="dataSource.id"
          :ref="`dataSourceForm_${dataSource.id}`"
          :key="dataSource.id"
          :builder="builder"
          :data-source="dataSource"
          :page="page"
          :default-values="dataSource"
          :integrations="integrations"
          :loading="dataSourcesLoading.includes(dataSource.id)"
          @delete="deleteDataSource(dataSource)"
          @values-changed="updateDataSource(dataSource, $event)"
        />
      </div>

      <template v-else>
        <div class="data-source-context__none">
          <div class="data-source-context__none-title">
            {{ $t('dataSourceContext.noDataSourceTitle') }}
          </div>
          <div class="data-source-context__none-description">
            {{ $t('dataSourceContext.noDataSourceMessage') }}
          </div>
        </div>
      </template>

      <ButtonText
        icon="iconoir-plus"
        type="secondary"
        :loading="creationInProgress"
        @click="createDataSource()"
      >
        {{ $t('dataSourceContext.addDataSource') }}
      </ButtonText>
    </template>
  </Context>
</template>

<script>
import context from '@baserow/modules/core/mixins/context'
import DataSourceForm from '@baserow/modules/builder/components/dataSource/DataSourceForm'
import { mapActions } from 'vuex'
import _ from 'lodash'
import { clone } from '@baserow/modules/core/utils/object'
import { notifyIf } from '@baserow/modules/core/utils/error'

export default {
  name: 'DataSourceContext',
  components: { DataSourceForm },
  mixins: [context],
  inject: ['builder'],
  props: {
    page: {
      type: Object,
      required: true,
    },
  },
  data() {
    return {
      state: 'loaded',
      creationInProgress: false,
      onGoingUpdate: {},
      dataSourcesLoading: [],
    }
  },
  computed: {
    integrations() {
      return this.$store.getters['integration/getIntegrations'](this.builder)
    },
    dataSources() {
      return this.$store.getters['dataSource/getPageDataSources'](this.page)
    },
  },
  methods: {
    ...mapActions({
      actionFetchIntegrations: 'integration/fetch',
      actionCreateDataSource: 'dataSource/create',
      actionUpdateDataSource: 'dataSource/debouncedUpdate',
      actionDeleteDataSource: 'dataSource/delete',
      actionFetchDataSources: 'dataSource/fetch',
    }),
    async shown() {
      try {
        await Promise.all([
          this.actionFetchIntegrations({
            application: this.builder,
          }),
        ])
      } catch (error) {
        notifyIf(error)
      }
    },
    async createDataSource() {
      this.creationInProgress = true
      try {
        await this.actionCreateDataSource({
          page: this.page,
          values: {},
        })
      } catch (error) {
        notifyIf(error)
      }
      this.creationInProgress = false
    },
    async updateDataSource(dataSource, newValues) {
      // We only need to set the loading state if the integration is updated
      if (
        newValues.integration_id !== null &&
        newValues.integration_id !== undefined
      ) {
        this.dataSourcesLoading.push(dataSource.id)
      }

      const differences = Object.fromEntries(
        Object.entries(newValues).filter(
          ([key, value]) => !_.isEqual(value, dataSource[key])
        )
      )

      if (Object.keys(differences).length > 0) {
        try {
          await this.actionUpdateDataSource({
            page: this.page,
            dataSourceId: dataSource.id,
            values: clone(differences),
          })
          if (differences.type) {
            this.$refs[`dataSourceForm_${dataSource.id}`][0].reset()
          }
        } catch (error) {
          // Restore the previously saved values from the store
          this.$refs[`dataSourceForm_${dataSource.id}`][0].reset()
          notifyIf(error)
        }
      }

      this.dataSourcesLoading = this.dataSourcesLoading.filter(
        (id) => id !== dataSource.id
      )
    },
    async deleteDataSource(dataSource) {
      try {
        await this.actionDeleteDataSource({
          page: this.page,
          dataSourceId: dataSource.id,
        })
      } catch (error) {
        notifyIf(error)
      }
    },
  },
}
</script>