import {useEffect} from 'react'

// the consumer face of a per-id detail store: the entity plus the flags of
// the load that fills it. stores export matching adapter objects (crumbDetail,
// trailDetail, profileDetail); global and composite lookups match structurally
export type DetailResource<T> = {
  useData: (id: string) => T | undefined
  useLoading: (id: string) => boolean
  useError: (id: string) => string | null
  useLoad: () => (id: string) => Promise<void>
}

// adapts a detail resource into a screen's moving parts: the mount load and
// the raw flags. refresh refetches on every visit (viewer screens); without
// it only a missing entity loads (editors touching a copy they may already
// hold). the settled-miss policy — redirect, error state — stays with the
// screen
export const useDetail = <T>(
  resource: DetailResource<T>,
  id: string,
  {refresh = true} = {},
) => {
  const data = resource.useData(id)
  const loading = resource.useLoading(id)
  const error = resource.useError(id)
  const load = resource.useLoad()

  const missing = data === undefined
  useEffect(() => {
    if (refresh || missing) void load(id)
    // the entity filling in must not re-arm the load — only a new id does
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [refresh, id, load])

  return {data, loading, error, retry: () => void load(id)}
}
