<script>
  import { getContext, setContext, onMount } from "svelte"
  import { dataSourceStore, createContextStore } from "stores"
  import { ActionTypes } from "constants"
  import { generate } from "shortid"

  export let data
  export let actions
  export let key

  // Clone and create new data context for this component tree
  const context = getContext("context")
  const component = getContext("component")
  const newContext = createContextStore(context)
  setContext("context", newContext)

  const providerKey = key || $component.id

  // Generate a permanent unique ID for this component and use it to register
  // any datasource actions
  const instanceId = generate()

  // Keep previous state around so we can avoid updating unless necessary
  let lastDataKey
  let lastActionsKey

  $: provideData(data)
  $: provideActions(actions, instanceId)

  const provideData = newData => {
    const dataKey = JSON.stringify(newData)
    if (dataKey !== lastDataKey) {
      newContext.actions.provideData(providerKey, newData)
      lastDataKey = dataKey
    }
  }

  const provideActions = newActions => {
    const actionsKey = JSON.stringify(newActions)
    if (actionsKey !== lastActionsKey) {
      lastActionsKey = actionsKey
      newActions?.forEach(({ type, callback, metadata }) => {
        newContext.actions.provideAction(providerKey, type, callback)

        // Register any "refresh datasource" actions with a singleton store
        // so we can easily refresh data at all levels for any datasource
        if (type === ActionTypes.RefreshDatasource) {
          const { dataSource } = metadata || {}
          dataSourceStore.actions.registerDataSource(
            dataSource,
            instanceId,
            callback
          )
        }
      })
    }
  }

  onMount(() => {
    // Unregister all datasource instances when unmounting this provider
    return () => dataSourceStore.actions.unregisterInstance(instanceId)
  })
</script>

<slot />
