import { computed } from "vue"
import { useObservable } from "@vueuse/rxjs"
import getStateObservable from "@racletteCore/lib/observableHelpers/getStateObservable"
import type { Observable } from "rxjs"

/**
 * Filters an object of objects based on nested property values
 * @param data The source data object to filter
 * @param filter An object where keys are dot-notation paths and values are the expected values
 * @returns A new object containing only the items that match all filter criteria
 */
const filterObjects = <T extends Record<string, any>>(
  data: Record<string, T>,
  filter: Record<string, any>,
): Record<string, T> => {
  const result: Record<string, T> = {}

  // Helper function to get a nested property using a dot-notation path
  const getNestedProperty = (obj: any, path: string): any =>
    path
      .split(".")
      .reduce(
        (prev, curr) =>
          prev && prev[curr] !== undefined ? prev[curr] : undefined,
        obj,
      )

  // Iterate through each item in the data object
  Object.entries(data).forEach(([key, item]) => {
    // Check if the item matches all filter criteria
    const matchesAllCriteria = Object.entries(filter).every(
      ([filterPath, filterValue]) => {
        const propertyValue = getNestedProperty(item, filterPath)

        return propertyValue === filterValue
      },
    )

    // If the item matches all criteria, add it to the result
    if (matchesAllCriteria) {
      result[key] = item
    }
  })

  return result
}

// Example usage:
// const filteredData = filterObjects(sourceData, {'_source.title': 'ADMIN', '_type': 'tag'});

// TODO find a better way to handle the filter here. It would be nice if the observable would from the beginning only contain what we want want instead of just returning a filtered subset of it
export const useVueStateObservableHelper =
  () =>
  (
    path: string | string[] = [],
    filter: Record<string, any> = {},
  ): { state: Object; observable$: Observable<any> } => {
    const observable$ = getStateObservable(path)

    const state = computed(() => {
      if (observable$) {
        const result = useObservable(observable$).value

        if (Object.keys(result).length > 0 && Object.keys(filter).length > 0) {
          return filterObjects(result, filter)
        }

        return result
      }

      return null
    })

    return { observable$, state }
  }
