"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { ArrowLeft } from "lucide-react"
import { resolvePublicShareEditReturnTo } from "@/lib/drive/public-share-url"

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): 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 = "onlyoffice-docs-api-public"
    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 */
    }
  }
  document.getElementById(id)?.replaceChildren()
}

function OnlyOfficeMount({
  editorId,
  documentServerUrl,
  config,
  onError,
}: {
  editorId: string
  documentServerUrl: string
  config: Record<string, unknown>
  onError: (message: string) => void
}) {
  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: {
        onError: (event: { data?: { errorDescription?: string; errorCode?: number } }) => {
          const msg =
            event?.data?.errorDescription ||
            (event?.data?.errorCode != null
              ? `OnlyOffice error ${event.data.errorCode}`
              : "Erreur OnlyOffice.")
          onErrorRef.current(msg)
        },
      },
      ...parsed,
    }
    void loadDocsApi(documentServerUrl)
      .then(() => {
        if (cancelled || !window.DocsAPI) return
        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])

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

export function PublicOfficeEditor({
  token,
  filePath,
  password,
  returnTo,
  mode = "edit",
}: {
  token: string
  filePath: string
  password?: string
  returnTo?: string | null
  mode?: "edit" | "view"
}) {
  const instanceSeq = useRef(0)
  const guestId = useRef(
    typeof crypto !== "undefined" && "randomUUID" in crypto
      ? crypto.randomUUID()
      : `guest-${Date.now()}`
  )
  const [config, setConfig] = useState<Record<string, unknown> | null>(null)
  const [serverUrl, setServerUrl] = useState("")
  const [editorId, setEditorId] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const backHref = useMemo(
    () => resolvePublicShareEditReturnTo(token, returnTo, filePath),
    [token, returnTo, filePath]
  )

  useEffect(() => {
    let cancelled = false
    setConfig(null)
    setServerUrl("")
    setEditorId(null)
    setError(null)

    void (async () => {
      try {
        const res = await fetch(
          `/api/v1/drive/public/shares/${encodeURIComponent(token)}/office/session`,
          {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              path: filePath,
              mode,
              password: password ?? "",
              guest_id: guestId.current,
            }),
          }
        )
        if (!res.ok) throw new Error("session_failed")
        const data = (await res.json()) as {
          config: Record<string, unknown>
          serverUrl: string
        }
        if (cancelled) return
        instanceSeq.current += 1
        setConfig(data.config)
        setServerUrl(data.serverUrl || process.env.NEXT_PUBLIC_ONLYOFFICE_URL || "")
        setEditorId(`ultidrive-public-editor-${instanceSeq.current}`)
      } catch {
        if (!cancelled) setError("Impossible de charger l’éditeur.")
      }
    })()

    return () => {
      cancelled = true
    }
  }, [token, filePath, password, mode])

  const handleEditorError = useCallback((message: string) => {
    setError(message)
  }, [])

  if (error) {
    return (
      <div className="flex h-dvh flex-col items-center justify-center gap-4">
        <p className="text-destructive">{error}</p>
        <Button asChild variant="outline">
          <Link href={backHref}>
            <ArrowLeft className="mr-2 h-4 w-4" />
            Retour
          </Link>
        </Button>
      </div>
    )
  }

  if (!config || !editorId || !serverUrl) {
    return <p className="p-8 text-center text-muted-foreground">Ouverture du document…</p>
  }

  return (
    <div className="flex h-dvh flex-col">
      <div className="flex h-12 shrink-0 items-center gap-2 border-b border-border px-3 ultidrive-editor-chrome">
        <Button variant="ghost" size="sm" asChild>
          <Link href={backHref}>
            <ArrowLeft className="mr-1 h-4 w-4" />
            Partage
          </Link>
        </Button>
        <span className="truncate text-sm font-medium">{filePath.split("/").pop()}</span>
      </div>
      <div className="relative min-h-0 flex-1">
        <OnlyOfficeMount
          editorId={editorId}
          documentServerUrl={serverUrl.replace(/\/$/, "")}
          config={config}
          onError={handleEditorError}
        />
      </div>
    </div>
  )
}
