import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {Stack, Button, Inline} from '@sanity/ui'
import {PatchEvent, set, unset} from 'sanity'
import {SlugInput, type SlugInputProps} from 'sanity'
import {useClient, useFormValue} from 'sanity'

type PersonDoc = {name?: string}

function slugify(input: string) {
  const folded = input
    .normalize('NFKD')
    .replace(/\p{M}+/gu, '')
    .replace(/ß/g, 'ss')
    .replace(/ø/g, 'o')
    .replace(/đ/g, 'd')
    .replace(/ł/g, 'l')

  return folded
    .toLowerCase()
    .trim()
    .replace(/[^\p{L}\p{N}]+/gu, '-')
    .replace(/(^-|-$)+/g, '')
    .slice(0, 96)
}

export function WorkSlugInput(props: SlugInputProps) {
  const client = useClient({apiVersion: '2026-01-01'})

  const title = (useFormValue(['title']) as string) || ''
  const composerRef = (useFormValue(['composer', '_ref']) as string) || ''
  const arrangerRef = (useFormValue(['arranger', '_ref']) as string) || ''

  const [composerName, setComposerName] = useState<string>('')
  const lastFetchedRef = useRef<string>('')

  const [arrangerName, setArrangerName] = useState<string>('')
  const lastFetchedArrangerRef = useRef<string>('')

  const lastAutoSlugRef = useRef<string>('')

  const desiredSource = useMemo(() => {
    const parts = [composerName, title, arrangerName ? `arr ${arrangerName}` : null].filter(Boolean)
    return parts.join(' ')
  }, [composerName, title, arrangerName])

  const generateSlug = useCallback(() => {
    if (!desiredSource) return

    const nextSlug = slugify(desiredSource)
    lastAutoSlugRef.current = nextSlug

    props.onChange(PatchEvent.from(nextSlug ? set({_type: 'slug', current: nextSlug}) : unset()))
  }, [desiredSource, props.onChange])

  useEffect(() => {
    let alive = true

    async function run() {
      if (!composerRef) {
        setComposerName('')
        lastFetchedRef.current = ''
        return
      }
      if (lastFetchedRef.current === composerRef) return

      lastFetchedRef.current = composerRef

      const doc = await client.fetch<PersonDoc>(`*[_type == "composer" && _id == $id][0]{name}`, {
        id: composerRef,
      })

      if (!alive) return
      setComposerName(doc?.name || '')
    }

    run()

    return () => {
      alive = false
    }
  }, [composerRef, client])

  useEffect(() => {
    let alive = true

    async function run() {
      if (!arrangerRef) {
        setArrangerName('')
        lastFetchedArrangerRef.current = ''
        return
      }
      if (lastFetchedArrangerRef.current === arrangerRef) return

      lastFetchedArrangerRef.current = arrangerRef

      const doc = await client.fetch<PersonDoc>(`*[_type == "composer" && _id == $id][0]{name}`, {
        id: arrangerRef,
      })

      if (!alive) return
      setArrangerName(doc?.name || '')
    }

    run()

    return () => {
      alive = false
    }
  }, [arrangerRef, client])

  useEffect(() => {
    if (!composerName || !title) return

    const current = props.value?.current || ''
    const nextSlug = slugify(desiredSource)

    if (!lastAutoSlugRef.current && current && current === nextSlug) {
      lastAutoSlugRef.current = current
      return
    }

    if (!current || current === lastAutoSlugRef.current) {
      lastAutoSlugRef.current = nextSlug
      props.onChange(PatchEvent.from(set({_type: 'slug', current: nextSlug})))
    }
  }, [composerName, arrangerName, title, desiredSource, props.value?.current, props.onChange])

  return (
    <Stack space={3}>
      <SlugInput {...props} />

      <Stack space={2}>
        <Inline space={2}>
          <Button
            text="Generate"
            mode="default"
            onClick={generateSlug}
            disabled={!composerName || !title}
          />
        </Inline>
      </Stack>
    </Stack>
  )
}
