import { mapGetters } from 'vuex'
import applicationContextMixin from '@baserow/modules/builder/mixins/applicationContext'
import { CurrentRecordDataProviderType } from '@baserow/modules/builder/dataProviderTypes'

export default {
  mixins: [applicationContextMixin],
  computed: {
    /**
     * Returns the schema which the service schema property selector
     * will use when listing the available properties. If the collection
     * element is not nested, we'll use the selected data source's schema,
     * otherwise if it's nested, we use the current record's data schema.
     * @returns {Object} - The schema to use.
     */
    propertySelectorSchema() {
      return this.$registry
        .get('builderDataProvider', CurrentRecordDataProviderType.getType())
        .getDataSchema({
          ...this.applicationContext,
          /**
           * We want to use the data_source_id of this element...
           */
          allowSameElement: true,
          /**
           * but, we don't want to use the schema property of this element as we are
           * defining it.
           */
          followSameElementSchemaProperties: false,
        })
    },
    /**
     * A convenience computed method which returns if this element has
     * a collection ancestor. This influences a few things, such as whether
     * the schema property selector is available, or whether the data source
     * dropdown is available.
     * @returns {boolean} - Whether the element has a collection ancestor.
     */
    hasCollectionAncestor() {
      const { element } = this.applicationContext
      const elementType = this.$registry.get('element', element.type)
      return elementType.hasCollectionAncestor(this.page, element)
    },
    /**
     * In collection element forms, the ability to view paging options
     * (e.g. items per page, or styling the load more button) is dependent
     * on whether the selected data source returns a list. When a single row
     * data source is used, we use all of its records to iterate with, so no
     * paging options are available.
     * @returns {boolean} - Whether the paging options are available.
     */
    pagingOptionsAvailable() {
      return this.selectedDataSourceReturnsList
    },
    /**
     * In collection element forms, the ability to choose a data source
     * is dependent on whether the element has a collection ancestor. If
     * it's a root-level collection element, designers can choose one,
     * otherwise only schema properties can be chosen.
     * @returns {boolean} - Whether the data source dropdown is available.
     */
    dataSourceDropdownAvailable() {
      return !this.hasCollectionAncestor
    },
    /**
     * - If the collection element is a root element:
     *     - If a non-list-type data source is selected:
     *         - Designer MUST then choose a SchemaPropertySelector to use
     *     - If a list-type data source is selected:
     *         - The SchemaPropertySelector is hidden and no longer usable.
     * - If the collection element is nested:
     *    - The data source Dropdown component is hidden and no longer usable.
     *    - The SchemaPropertySelector can choose a single property from the current_record schema.
     * @returns {boolean}
     */
    propertySelectorAvailable() {
      if (!this.hasCollectionAncestor) {
        // If we don't have a data source, or
        // We do, and it returns a list, then the schema selector isn't available.
        if (!this.selectedDataSource || this.selectedDataSourceReturnsList) {
          return false
        }
      }
      return true
    },
    sharedPage() {
      return this.$store.getters['page/getSharedPage'](this.builder)
    },
    /**
     * Returns all data sources that are available to the current page.
     * @returns {Array} - The data sources the page designer can choose from.
     */
    dataSources() {
      const pages = [this.sharedPage, this.page]
      return this.$store.getters['dataSource/getPagesDataSources'](
        pages
      ).filter((dataSource) => dataSource.type)
    },
    selectedDataSource() {
      if (!this.values.data_source_id) {
        return null
      }
      const pages = [this.sharedPage, this.page]
      return this.$store.getters['dataSource/getPagesDataSourceById'](
        pages,
        this.values.data_source_id
      )
    },
    selectedDataSourceType() {
      if (!this.selectedDataSource || !this.selectedDataSource.type) {
        return null
      }
      return this.$registry.get('service', this.selectedDataSource.type)
    },
    selectedDataSourceReturnsList() {
      return this.selectedDataSourceType?.returnsList
    },
    maxItemPerPage() {
      if (!this.selectedDataSourceType) {
        return 20
      }
      return this.selectedDataSourceType.maxResultLimit
    },
    elementHasContent() {
      const { element } = this.applicationContext
      return this.$store.getters['elementContent/getElementContent'](element)
    },
    ...mapGetters({
      element: 'element/getSelected',
    }),
  },
  watch: {
    /**
     * When the data source is changed, we need to reset the schema property
     */
    'values.data_source_id'(newValue, oldValue) {
      if (oldValue && newValue !== oldValue) {
        this.values.schema_property = null
      }
    },
    /**
     * When the array of data sources available to this page changes, ensure
     * that the selected data source is still available. If it's not, reset
     * the `data_source_id` to null`.
     */
    'dataSources.length'(newValue, oldValue) {
      if (this.values.data_source_id && oldValue > newValue) {
        if (
          !this.dataSources.some(({ id }) => id === this.values.data_source_id)
        ) {
          // Remove the data_source_id if the related dataSource has been deleted.
          this.values.data_source_id = null
          // And delete element content (not handled by the element event)
          this.$store.dispatch('elementContent/clearElementContent', {
            element: this.element,
          })
        }
      }
    },
  },
}