"use client"

import { useEffect, useRef } from "react"

type DocEditorInstance = { destroyEditor: () => void }

declare global {
  interface Window {
    DocsAPI?: {
      DocEditor: new (id: string, config: Record<string, unknown>) => DocEditorInstance
    }
    DocEditor?: { instances: Record<string, DocEditorInstance | undefined> }
  }
}

let docsApiLoad: Promise<void> | null = null

function loadDocsApi(documentServerUrl: string, scriptId: string): Promise<void> {
  if (window.DocsAPI) return Promise.resolve()
  if (docsApiLoad) return docsApiLoad

  const base = documentServerUrl.replace(/\/$/, "") + "/"
  docsApiLoad = new Promise((resolve, reject) => {
    const script = document.createElement("script")
    script.id = scriptId
    script.src = `${base}web-apps/apps/api/documents/api.js`
    script.async = true
    script.onload = () => resolve()
    script.onerror = () => {
      docsApiLoad = null
      reject(new Error(`Error load DocsAPI from ${base}`))
    }
    document.body.appendChild(script)
  })

  return docsApiLoad
}

function destroyDocEditor(id: string) {
  const inst = window.DocEditor?.instances?.[id]
  if (inst) {
    try {
      inst.destroyEditor()
    } catch {
      /* ignore */
    }
    delete window.DocEditor!.instances[id]
  }
  document.getElementById(id)?.replaceChildren()
}

export function OnlyOfficeMount({
  editorId,
  documentServerUrl,
  config,
  onError,
  scriptId = "onlyoffice-docs-api",
}: {
  editorId: string
  documentServerUrl: string
  config: Record<string, unknown>
  onError: (message: string) => void
  scriptId?: string
}) {
  const configJson = JSON.stringify(config)
  const onErrorRef = useRef(onError)
  onErrorRef.current = onError

  useEffect(() => {
    let cancelled = false
    const id = editorId
    const parsed = JSON.parse(configJson) as Record<string, unknown>
    const editorConfig: Record<string, unknown> = {
      type: "desktop",
      width: "100%",
      height: "100%",
      events: {
        onDocumentReady: () => {
          /* loaded */
        },
        onError: (event: { data?: { errorCode?: number; errorDescription?: string } }) => {
          const code = event?.data?.errorCode
          const desc = event?.data?.errorDescription
          const msg =
            desc ||
            (code != null ? `OnlyOffice error ${code}` : "Erreur OnlyOffice.")
          onErrorRef.current(msg)
        },
      },
      ...parsed,
    }

    void loadDocsApi(documentServerUrl, scriptId)
      .then(() => {
        if (cancelled) return
        if (!window.DocsAPI) throw new Error("DocsAPI is not defined")
        destroyDocEditor(id)
        if (!window.DocEditor) window.DocEditor = { instances: {} }
        const editor = new window.DocsAPI.DocEditor(id, editorConfig)
        window.DocEditor.instances[id] = editor
      })
      .catch((err: unknown) => {
        if (!cancelled) {
          onErrorRef.current(
            err instanceof Error ? err.message : "Impossible de charger OnlyOffice.",
          )
        }
      })

    return () => {
      cancelled = true
      destroyDocEditor(id)
    }
  }, [editorId, documentServerUrl, configJson, scriptId])

  return <div id={editorId} className="h-full w-full min-h-0" />
}
