import {type SanityDocument} from '@sanity/types'
import {useEffect, useState} from 'react'
import {useAsObservable} from 'react-rx'
import {from, of} from 'rxjs'
import {catchError, debounceTime, switchMap} from 'rxjs/operators'
import {isRecord, useSource} from 'sanity'

const isSanityDocument = (value: unknown): value is SanityDocument =>
  isRecord(value) && typeof value._id === 'string' && typeof value._type === 'string'

export function usePreviewUrl(value: Partial<SanityDocument> | undefined): string | undefined {
  const [previewUrl, setPreviewUrl] = useState<string | undefined>(undefined)
  const [error, setError] = useState<unknown>(null)
  const {resolveProductionUrl} = useSource().document
  // @todo refactor out of useAsObservable, and instead use `of() + useMemoObservable` like we did for `useLoadableFromCreateLoadable`
  const value$ = useAsObservable(value)

  if (error) throw error

  useEffect(() => {
    value$
      .pipe(
        // this so that the preview URL isn't fetched on every keystroke
        debounceTime(500),
        switchMap((document) =>
          isSanityDocument(document) ? from(resolveProductionUrl({document})) : of(undefined),
        ),
        catchError((e) => {
          const message = isRecord(e) && typeof e.message === 'string' ? e.message : 'Unknown error'
          throw new Error(`An error was thrown while trying to get your preview url: ${message}`)
        }),
      )
      .subscribe({
        next: setPreviewUrl,
        error: setError,
      })
  }, [resolveProductionUrl, value$])

  return previewUrl
}
