import { computed, ref, watch, onUnmounted } from "vue"
import { useObservable } from "@vueuse/rxjs"
import { $queryApi } from "@racletteCore/lib/data/dataApi"
import type { QueryApiQuery, QueryMethods } from "@racletteCore/types"
import type {
  VueQueryParamsInput,
  VueStoreActionsPayload,
} from "../types/DataApi"
import { toQueryParamsSource } from "../lib/queryParamsSource"
import { difference } from "ramda"
import getStateObservable from "@racletteCore/lib/observableHelpers/getStateObservable"
import type { Observable } from "rxjs"

const subscriber$ = {}
// the counter is just here to remember how often we have returned the same subscriber per actionId (in case of shared actions) this is neede for proper unsubscribe
const subscriberCounter = {}
export const useVueQueryObservableHelper = (
  instanceActionId,
  target,
  { params = {}, options = {} }: VueStoreActionsPayload = {},
): QueryMethods => {
  const paramsSource = toQueryParamsSource(params)
  const dataObservable$ = ref<Observable<unknown>>()

  const data = computed(() => {
    if (dataObservable$.value) {
      const result = useObservable(dataObservable$.value).value
      return result
    }

    return null
  })

  let coreQuery

  if (subscriber$[instanceActionId]) {
    subscriberCounter[instanceActionId] += 1
    coreQuery = subscriber$[instanceActionId]
  } else {
    subscriberCounter[instanceActionId] = 1
    coreQuery = $queryApi(instanceActionId, target, { params: paramsSource, options })
  }
  subscriber$[instanceActionId] = coreQuery
  const queryRef = useObservable<QueryApiQuery>(coreQuery.query$)
  const errorObservable = useObservable(coreQuery.error$)
  const responseRef = useObservable<QueryApiQuery>(coreQuery.response$)
  if (options.useStore !== false) {
    watch(queryRef, (value, oldValue) => {
      const newUUIDS = value?.uuids || []
      const oldUUIDS = oldValue?.uuids || []
      if (
        difference(newUUIDS, oldUUIDS).length ||
        difference(oldUUIDS || [], newUUIDS).length
      ) {
        dataObservable$.value = getStateObservable([
          "data",
          newUUIDS,
          "_source",
        ])
      }
    })
  }

  onUnmounted(() => {
    subscriberCounter[instanceActionId] -= 1
    if (subscriberCounter[instanceActionId] === 0) {
      subscriber$[instanceActionId].remove()
      delete subscriber$[instanceActionId]
      delete subscriberCounter[instanceActionId]
    }
  })
  const queryObject = {
    query: queryRef,
    isLoading: computed(() => {
      return queryRef.value?.loading
    }),
    data,
    dataArr: computed(() => {
      return data.value ? Object.values(data.value) : []
    }),
    response: responseRef,
    execute: (executeParams?: VueQueryParamsInput) =>
      executeParams === undefined
        ? coreQuery.execute()
        : coreQuery.execute(toQueryParamsSource(executeParams)),
    uuids: coreQuery.uuids$,
    remove: coreQuery.remove,
    clear: coreQuery.clear,
    error: computed(() => {
      return errorObservable.value
    }),
  }
  if (options.useStore === false) delete queryObject.uuids
  return queryObject
}
