'use client'

import { useEffect, useRef, useState } from 'react'

/**
 * Visor 3D del personaje. Usa la librería `wow-model-viewer` (generateModels), que a
 * su vez necesita jQuery y el ZamModelViewer de wowhead (wow.zamimg.com) cargados en
 * global. Se cargan bajo demanda solo en esta ficha.
 *
 * OJO: es integración cliente que depende de un CDN externo (zamimg) y no se puede
 * verificar sin navegador; por eso todo va envuelto en try/catch y con un temporizador
 * de reserva: si el modelo no aparece, se muestra un aviso en lugar de romper la ficha.
 *
 * El equipo se pasa como {slot, entry, displayid}; la librería mapea cada ítem a su
 * slot del visor. displayid = transmog si lo hay, si no el del ítem equipado.
 */

// Same-origin (proxy /modelviewer/* -> zamimg en next.config): evita el bloqueo CORS
// del visor, que es lo que dejaba el modelo «no disponible».
const ZAM_VIEWER = '/modelviewer/live/viewer/viewer.min.js'
const JQUERY = 'https://code.jquery.com/jquery-3.7.1.min.js'
const CONTENT_PATH = '/modelviewer/live/'

type Win = typeof window & { jQuery?: unknown; $?: unknown; ZamModelViewer?: unknown; CONTENT_PATH?: string }

function loadScript(src: string): Promise<void> {
  return new Promise((resolve, reject) => {
    if (document.querySelector(`script[src="${src}"]`)) return resolve()
    const s = document.createElement('script')
    s.src = src
    s.async = true
    s.onload = () => resolve()
    s.onerror = () => reject(new Error(`no se pudo cargar ${src}`))
    document.head.appendChild(s)
  })
}

export function ArmoryModel3D({
  race,
  gender,
  equip,
  labels,
}: {
  race: number
  gender: number
  equip: { slot: number; entry: number; displayid: number }[]
  labels: { loading: string; unavailable: string }
}) {
  const ref = useRef<HTMLDivElement>(null)
  const [state, setState] = useState<'loading' | 'ok' | 'fail'>('loading')

  useEffect(() => {
    let cancelled = false
    const failTimer = setTimeout(() => !cancelled && setState((s) => (s === 'loading' ? 'fail' : s)), 12000)

    ;(async () => {
      try {
        const w = window as Win
        w.CONTENT_PATH = CONTENT_PATH
        await loadScript(JQUERY)
        await loadScript(ZAM_VIEWER)
        // La librería es ESM y usa jQuery/ZamModelViewer globales.
        const mv = await import('wow-model-viewer')
        if (cancelled || !ref.current) return

        // La resolución de ítems hace consultas al CDN y puede fallar; si falla, se
        // renderiza al menos el personaje sin equipo en vez de dejar la ficha vacía.
        let items: unknown[] = []
        try {
          items = await mv.findItemsInEquipments(
            equip.map((e) => ({ slot: e.slot, entry: e.entry, displayid: e.displayid })),
            'live',
          )
        } catch (err) {
          console.warn('[armory-3d] no se pudieron resolver los ítems del modelo:', err)
        }
        if (cancelled || !ref.current) return

        ref.current.id = ref.current.id || `armory-model-${race}-${gender}`
        await mv.generateModels(1, `#${ref.current.id}`, { race, gender, items }, 'live')
        if (!cancelled) {
          clearTimeout(failTimer)
          setState('ok')
        }
      } catch (err) {
        console.error('[armory-3d] no se pudo cargar el visor 3D:', err)
        if (!cancelled) {
          clearTimeout(failTimer)
          setState('fail')
        }
      }
    })()

    return () => {
      cancelled = true
      clearTimeout(failTimer)
    }
    // solo al montar / cambiar de personaje
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [race, gender])

  return (
    <div className="armory-model">
      <div ref={ref} className="armory-model-canvas" />
      {state === 'loading' && <p className="armory-hint">{labels.loading}</p>}
      {state === 'fail' && <p className="armory-hint">{labels.unavailable}</p>}
    </div>
  )
}
