import {useEffect} from 'react'

import {matchesFilter} from '@/lib/map'
import {
  useLoadRecentCrumbs,
  useRecentCrumbs,
  useRecentCrumbsLoading,
} from '@/stores/crumbs'
import {
  useFriends,
  useFriendsLoading,
  useLoadFriends,
} from '@/stores/friends'
import {
  useSearch,
  useSearchCrumbs,
  useSearchError,
  useSearchLoading,
  useSearchTrails,
  useSearchUsers,
} from '@/stores/search'
import {useRefreshTags, useTags} from '@/stores/tags'
import {
  useLoadTrails,
  useTrails,
  useTrailsLoading,
} from '@/stores/trails'

const RECENT_LIMIT = 10
const PEOPLE_LIMIT = 5

export type SearchScope = 'all' | 'crumbs' | 'trails' | 'people'

// owns the search screen's store wiring and derivations: recents shown
// until results exist, stale results kept visible while a fresh query
// loads, and a selected tag narrowing scope to crumbs
export const useSearchResults = (
  query: string,
  scope: SearchScope,
  activeTag: string | null,
) => {
  const search = useSearch()
  const loadFeed = useLoadRecentCrumbs()
  const refreshTrails = useLoadTrails()
  const refreshFriends = useLoadFriends()
  const refreshTags = useRefreshTags()

  const tags = useTags()
  const recentCrumbs = useRecentCrumbs()
  const recentTrails = useTrails()
  const recentFriends = useFriends()
  const recentCrumbsLoading = useRecentCrumbsLoading()
  const recentTrailsLoading = useTrailsLoading()
  const recentFriendsLoading = useFriendsLoading()
  const resultCrumbs = useSearchCrumbs()
  const resultTrails = useSearchTrails()
  const resultUsers = useSearchUsers()
  const searchLoading = useSearchLoading()
  const searchError = useSearchError()

  useEffect(() => {
    void loadFeed()
    void refreshTrails()
    void refreshFriends()
    void refreshTags()
  }, [loadFeed, refreshTrails, refreshFriends, refreshTags])

  const hasQuery = query.trim().length > 0
  // while a fresh query is loading keep the current items visible
  // (recent on first search, prior results afterwards) instead of
  // flashing an empty state
  const showResults =
    hasQuery &&
    (!searchLoading ||
      resultCrumbs.length > 0 ||
      resultTrails.length > 0 ||
      resultUsers.length > 0)

  const crumbs = showResults
    ? resultCrumbs
    : recentCrumbs.slice(0, RECENT_LIMIT)
  const trails = showResults
    ? resultTrails
    : recentTrails.slice(0, RECENT_LIMIT)
  const users = (showResults ? resultUsers : recentFriends).slice(
    0,
    PEOPLE_LIMIT,
  )

  return {
    search,
    tags,
    hasQuery,
    showResults,
    // a tag only describes crumbs, so selecting one narrows to crumbs
    effectiveScope: activeTag ? 'crumbs' : scope,
    searching: hasQuery && searchLoading,
    error: hasQuery ? searchError : null,
    users,
    usersLoading: hasQuery ? searchLoading : recentFriendsLoading,
    crumbs: activeTag
      ? crumbs.filter((c) =>
          matchesFilter(c, {kind: 'tag', tag: activeTag}),
        )
      : crumbs,
    crumbsLoading: hasQuery ? searchLoading : recentCrumbsLoading,
    trails,
    trailsLoading: hasQuery ? searchLoading : recentTrailsLoading,
  }
}
