import { ref, computed, type Ref, type ComputedRef } from 'vue'
import { useFuse } from '@vueuse/integrations/useFuse'
import type { IFuseOptions, FuseResult } from 'fuse.js'

export interface FuzzySearchOptions<T = any> {
  /**
   * Fuse.js options for configuring the search behavior
   */
  fuseOptions?: IFuseOptions<T>
  /**
   * Maximum number of results to return
   */
  resultLimit?: number
  /**
   * Whether to return all items when search is empty
   */
  matchAllWhenSearchEmpty?: boolean
  /**
   * Debounce delay in milliseconds for search input
   */
  debounceMs?: number
  /**
   * Minimum search length before triggering search
   */
  minSearchLength?: number
}

export interface UseFuzzySearchReturn<T> {
  /**
   * Current search query
   */
  searchQuery: Ref<string>
  /**
   * Search results with Fuse.js scoring
   */
  results: ComputedRef<FuseResult<T>[]>
  /**
   * Filtered items (just the items without scoring)
   */
  filteredItems: ComputedRef<T[]>
  /**
   * Whether search is currently active
   */
  isSearching: ComputedRef<boolean>
  /**
   * Number of results found
   */
  resultCount: ComputedRef<number>
  /**
   * Clear the current search
   */
  clearSearch: () => void
  /**
   * Set the search query
   */
  setSearchQuery: (query: string) => void
  /**
   * Update the data to search through
   */
  updateData: (data: T[]) => void
}

/**
 * Composable for fuzzy search functionality using Fuse.js
 * 
 * @param data - The data to search through
 * @param options - Configuration options for the fuzzy search
 * @returns Object with search functionality and results
 * 
 * @example
 * ```ts
 * // Basic usage
 * const { searchQuery, results, filteredItems, clearSearch } = useFuzzySearch(
 *   products,
 *   {
 *     fuseOptions: {
 *       keys: ['name', 'description'],
 *       threshold: 0.3
 *     },
 *     resultLimit: 10,
 *     minSearchLength: 2
 *   }
 * )
 * 
 * // Integration with existing market functionality
 * const { searchQuery, filteredItems } = useFuzzySearch(
 *   marketStore.products,
 *   {
 *     fuseOptions: {
 *       keys: [
 *         { name: 'name', weight: 0.7 },
 *         { name: 'description', weight: 0.3 },
 *         { name: 'stallName', weight: 0.2 },
 *         { name: 'categories', weight: 0.1 }
 *       ],
 *       threshold: 0.3,
 *       ignoreLocation: true
 *     },
 *     resultLimit: 50,
 *     minSearchLength: 2
 *   }
 * )
 * ```
 */
export function useFuzzySearch<T = any>(
  data: Ref<T[]> | T[],
  options: FuzzySearchOptions<T> = {}
): UseFuzzySearchReturn<T> {
  const {
    fuseOptions = {
      // Default Fuse.js options
      threshold: 0.3,
      distance: 100,
      ignoreLocation: true,
      useExtendedSearch: false,
      minMatchCharLength: 1,
      shouldSort: true,
      findAllMatches: false,
      location: 0,
      isCaseSensitive: false,
      keys: []
    },
    resultLimit,
    matchAllWhenSearchEmpty = true,

    minSearchLength = 0
  } = options

  // Search query state
  const searchQuery = ref('')

  // Create the Fuse instance using VueUse integration
  const { results } = useFuse(
    searchQuery,
    data,
    {
      fuseOptions,
      resultLimit,
      matchAllWhenSearchEmpty
    }
  )

  // Computed properties
  const isSearching = computed(() => {
    const query = searchQuery.value.trim()
    return query.length >= minSearchLength
  })

  const filteredItems = computed(() => {
    return results.value.map(result => result.item)
  })

  const resultCount = computed(() => results.value.length)

  // Methods
  const clearSearch = () => {
    searchQuery.value = ''
  }

  const setSearchQuery = (query: string) => {
    searchQuery.value = query
  }

  const updateData = (_newData: T[]) => {
    // The useFuse composable automatically watches for data changes
    // so we just need to update the ref if it's reactive
    if (Array.isArray(data)) {
      // If data is not reactive, we need to handle this differently
      console.warn('Data is not reactive. Consider using ref() for the data parameter.')
    }
  }

  return {
    searchQuery,
    results,
    filteredItems,
    isSearching,
    resultCount,
    clearSearch,
    setSearchQuery,
    updateData
  }
} 