import { callGrouper } from '@baserow/modules/core/utils/function'

const GRACE_DELAY = 50 // ms before querying the backend with a get query

const groupGetNameCalls = callGrouper(GRACE_DELAY)

export default (client) => {
  return {
    fetchAll(pageId) {
      return client.get(`builder/page/${pageId}/data-sources/`)
    },
    create(pageId, values = {}, beforeId = null) {
      const payload = {
        page_id: pageId,
        ...values,
      }

      if (beforeId !== null) {
        payload.before_id = beforeId
      }

      return client.post(`builder/page/${pageId}/data-sources/`, payload)
    },
    update(dataSourceId, values) {
      return client.patch(`builder/data-source/${dataSourceId}/`, values)
    },
    delete(dataSourceId) {
      return client.delete(`builder/data-source/${dataSourceId}/`)
    },
    move(dataSourceId, beforeId) {
      return client.patch(`builder/data-source/${dataSourceId}/move/`, {
        before_id: beforeId,
      })
    },
    dispatch(dataSourceId, dispatchContext, { range }) {
      // Using POST Http method here is not Restful but it the cleanest way to send
      // data with the call without relying on GET parameter and serialization of
      // complex object.
      const params = {}
      if (range) {
        params.offset = range[0]
        params.count = range[1]
      }

      return client.post(
        `builder/data-source/${dataSourceId}/dispatch/`,
        dispatchContext,
        { params }
      )
    },
    dispatchAll(pageId, params) {
      return client.post(
        `builder/page/${pageId}/dispatch-data-sources/`,
        params
      )
    },
    /**
     * Group multiple calls in one query to optimize perfs
     */
    getRecordNames: groupGetNameCalls(async (argList) => {
      // [[dataSourceId, recordIds], ...]
      //    ->{ <dataSourceId>: Array<with all record ids> }
      const dataSourceMap = argList.reduce((acc, [dataSourceId, recordIds]) => {
        if (!acc[`${dataSourceId}`]) {
          acc[`${dataSourceId}`] = new Set()
        }
        recordIds.forEach(acc[`${dataSourceId}`].add, acc[`${dataSourceId}`])
        return acc
      }, {})

      const data = Object.fromEntries(
        await Promise.all(
          Object.entries(dataSourceMap).map(
            async ([dataSourceId, recordIds]) => {
              try {
                const { data } = await client.get(
                  `builder/data-source/${dataSourceId}/record-names/`,
                  {
                    params: {
                      record_ids: Array.from(recordIds)
                        .map((item) => `${item}`)
                        .join(','),
                    },
                  }
                )
                return [dataSourceId, data]
              } catch (e) {
                return [dataSourceId, e]
              }
            }
          )
        )
      )

      return (dataSourceId, recordIds) => {
        if (!data[dataSourceId]) {
          return null
        }
        if (data[dataSourceId] instanceof Error) {
          throw data[dataSourceId]
        }
        return Object.fromEntries(
          Object.entries(data[dataSourceId]).filter(([key]) =>
            recordIds.includes(parseInt(key))
          )
        )
      }
    }),
  }
}