import { useIsFocused } from '@react-navigation/native'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import type { IntentMenuSpec, SearchIntent } from './intents'
import { menuStore } from './MenuStore'
import type { MenuHandle } from './types'

// useScreenMenu — the public spec-driven API. Pages call this once with an
// IntentMenuSpec; rendering happens in the globally-mounted MenuBarToolbar.
//
// Search is a TOGGLE. The magnifier icon appears whenever a search intent is
// present; tapping it expands the inline morph. When mode is 'route-to', the
// magnifier navigates to routeTo / onRouteTo instead.

function findSearchIntent(spec: IntentMenuSpec): SearchIntent | undefined {
  for (const intent of spec.intents) {
    if (intent.kind === 'search') return intent
  }
  return undefined
}

export function useScreenMenu(spec: IntentMenuSpec): MenuHandle {
  const search = findSearchIntent(spec)
  // Inline search expands itself on mount — the finite-list screens want the
  // input visible right away. Route-mode search never expands; the magnifier
  // always navigates.
  const autoOpen = !!search && (search.mode ?? 'inline') === 'inline'
  const [searchActive, setSearchActive] = useState<boolean>(autoOpen)
  const isFocused = useIsFocused()
  const idRef = useRef<number | null>(null)

  const toggleSearch = useCallback(() => {
    if (!search) return
    if (search.mode === 'route') {
      search.onRouteTo?.()
      return
    }
    setSearchActive((prev) => !prev)
  }, [search])

  // Register / unregister on focus changes. Spec updates push through the
  // second effect below so callbacks always reference the latest state.
  useEffect(() => {
    if (!isFocused) {
      // Collapse any in-progress search when the screen loses focus. Otherwise
      // the hook's local state persists and the screen re-enters with the
      // search bar still expanded.
      setSearchActive(false)
      if (idRef.current !== null) {
        menuStore.unregister(idRef.current)
        idRef.current = null
      }
      return
    }
    if (idRef.current === null) {
      idRef.current = menuStore.register({ spec, searchActive, toggleSearch })
    }
    return () => {
      if (idRef.current !== null) {
        menuStore.unregister(idRef.current)
        idRef.current = null
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isFocused])

  // Push spec / state updates each render while we hold an active entry.
  useEffect(() => {
    if (idRef.current === null) return
    menuStore.update(idRef.current, { spec, searchActive, toggleSearch })
  })

  return { searchActive, setSearchActive }
}

// Local-state helper for screens whose search bar filters an in-memory list.
export function useSearchQuery(initial = ''): [string, (text: string) => void] {
  const [query, setQuery] = useState<string>(initial)
  return [query, setQuery]
}

// In-memory client-side filter. Screens that wire a search intent and filter
// a list by text fields use this to avoid redeclaring the same effect in
// every consumer (8+ copies pre-v3).
export function useFilteredList<T>(
  data: T[] | undefined,
  query: string,
  getFields: (item: T) => Array<string | undefined | null>
): T[] {
  return useMemo(() => {
    if (!data) return []
    const q = query.trim().toLowerCase()
    if (!q) return data
    return data.filter((item) =>
      getFields(item).some((field) => field?.toLowerCase().includes(q))
    )
  }, [data, query, getFields])
}
