import { computed, ref, watch, onUnmounted } from "vue"
import { useObservable } from "@vueuse/rxjs"
import { $writeDataApi } from "@racletteCore/lib/data/dataApi"
import type { DataApiMethods } from "@racletteCore/types"
import type {
  VueQueryParamsInput,
  VueStoreActionsPayload,
} from "../types/DataApi"
import { toQueryParamsSource } from "../lib/queryParamsSource"
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 useVueWriteOperationHelper = (
  instanceActionId,
  operationDefinition,
  { params = {}, options = {} }: VueStoreActionsPayload = {},
): DataApiMethods => {
  const paramsSource = toQueryParamsSource(params)
  let writeOperation
  const dataStoreObservable$ = ref<Observable<any>>()

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

    return null
  })

  if (subscriber$[instanceActionId]) {
    subscriberCounter[instanceActionId] += 1
    writeOperation = subscriber$[instanceActionId]
  } else {
    subscriberCounter[instanceActionId] = 1
    writeOperation = $writeDataApi(instanceActionId, operationDefinition, {
      params: paramsSource,
      options,
    })
  }

  subscriber$[instanceActionId] = writeOperation

  // Use the observables for reactive state
  const isLoadingObservable = useObservable(writeOperation.isLoading$)
  const dataObservable = useObservable(writeOperation.data$)
  const errorObservable = useObservable(writeOperation.error$)
  const responseRef = useObservable(writeOperation.response$)
  if (options.useStore !== false) {
    watch(dataObservable, (value, oldValue) => {
      const uuids = []
      if (dataObservable.value && Array.isArray(dataObservable.value)) {
        dataObservable.value.forEach((item) => {
          uuids.push(item._id)
        })
        dataStoreObservable$.value = getStateObservable([
          "data",
          uuids,
          "_source",
        ])
      }
    })
  }

  onUnmounted(() => {
    subscriberCounter[instanceActionId] -= 1
    if (subscriberCounter[instanceActionId] === 0) {
      // Clean up the observable subject
      if (subscriber$[instanceActionId]?.remove) {
        subscriber$[instanceActionId].remove()
      }
      delete subscriber$[instanceActionId]
      delete subscriberCounter[instanceActionId]
    }
    writeOperation.remove()
  })

  const operationObject = {
    isLoading: computed(() => {
      return isLoadingObservable.value
    }),
    data,
    dataArr: computed(() => {
      return data.value ? Object.values(data.value) : []
    }),
    response: responseRef,
    execute: (executeParams?: VueQueryParamsInput) =>
      executeParams === undefined
        ? writeOperation.execute()
        : writeOperation.execute(toQueryParamsSource(executeParams)),
    remove: writeOperation.remove,
    clear: writeOperation.clear,
    error: computed(() => {
      return errorObservable.value
    }),
  }

  return operationObject
}
