import type { ReactNode } from 'react'
import type { UseQueryResult } from '@tanstack/react-query'
import { AdminButton } from './Performative'

interface AsyncBoundaryProps<T> {
  query: UseQueryResult<T, Error>
  children: (data: T) => ReactNode
  /** Predicate + render for the "loaded but empty" state. */
  empty?: { when: (data: T) => boolean; render: () => ReactNode }
  /** Custom loading UI. Defaults to <SkeletonRows>. */
  loading?: ReactNode
  errorTitle?: string
  /** Number of skeleton rows in the default loading UI. */
  skeletonRows?: number
}

export default function AsyncBoundary<T>({
  query,
  children,
  empty,
  loading,
  errorTitle = 'Failed to load',
  skeletonRows = 3,
}: AsyncBoundaryProps<T>) {
  if (query.isLoading && query.data === undefined) {
    return <>{loading ?? <SkeletonRows count={skeletonRows} />}</>
  }
  if (query.isError) {
    return (
      <div className="async-error" role="alert">
        <div className="async-error-title">{errorTitle}</div>
        <div className="async-error-message">
          {query.error instanceof Error ? query.error.message : String(query.error)}
        </div>
        <AdminButton
          type="button"
          onClick={() => { void query.refetch() }}
          disabled={query.isFetching}
          loading={query.isFetching}
        >
          Retry
        </AdminButton>
      </div>
    )
  }
  if (query.data === undefined) return null
  if (empty && empty.when(query.data)) return <>{empty.render()}</>
  return <>{children(query.data)}</>
}

function SkeletonRows({ count }: { count: number }) {
  return (
    <div className="skeleton-stack" aria-hidden="true">
      {Array.from({ length: count }, (_, i) => (
        <div key={i} className="skeleton skeleton-row" />
      ))}
    </div>
  )
}
