"use client"

import dynamic from "next/dynamic"
import { memo, useCallback, useState } from "react"
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types"
import type { DocsGraphicDrawSavePayload } from "@/lib/drive/docs-graphic-draw-bridge"

export function docsExcalidrawEditorKey(drawScene: string | null): string {
  if (!drawScene) return "new-draw"
  return `draw-${drawScene.length}-${drawScene.slice(0, 48)}`
}

const ExcalidrawEditor = dynamic(
  async () => {
    await import("@excalidraw/excalidraw/index.css")
    const { Excalidraw, restoreElements, restoreAppState } = await import(
      "@excalidraw/excalidraw"
    )
    type ExcalidrawInitialDataState = import("@excalidraw/excalidraw/types").ExcalidrawInitialDataState
    type BinaryFiles = import("@excalidraw/excalidraw/types").BinaryFiles
    const { memo, useEffect, useMemo, useRef } = await import("react")

    function parseInitialData(drawScene: string | null): ExcalidrawInitialDataState | undefined {
      if (!drawScene) return undefined
      try {
        const data = JSON.parse(drawScene) as {
          elements?: Parameters<typeof restoreElements>[0]
          appState?: Parameters<typeof restoreAppState>[0]
          files?: BinaryFiles
        }
        const initialData: ExcalidrawInitialDataState = {
          elements: restoreElements(data.elements ?? [], null),
          appState: restoreAppState(data.appState ?? {}, null),
          files: data.files,
        }
        return initialData
      } catch {
        return undefined
      }
    }

    const Inner = memo(function Inner({
      drawScene,
      onReady,
    }: {
      drawScene: string | null
      onReady: (api: ExcalidrawImperativeAPI) => void
    }) {
      const apiRef = useRef<ExcalidrawImperativeAPI | null>(null)
      const initialData = useMemo(() => parseInitialData(drawScene), [drawScene])

      useEffect(() => {
        const api = apiRef.current
        if (!api || !drawScene) return
        const data = parseInitialData(drawScene)
        if (!data) return
        api.updateScene({
          elements: data.elements ?? [],
          appState: data.appState,
          files: data.files,
        })
      }, [drawScene])

      return (
        <div className="h-full min-h-0 w-full">
          <Excalidraw
            excalidrawAPI={(api) => {
              apiRef.current = api
              onReady(api)
            }}
            initialData={initialData}
            langCode="fr-FR"
            UIOptions={{
              canvasActions: {
                changeViewBackgroundColor: true,
                clearCanvas: true,
                export: false,
                loadScene: false,
                saveToActiveFile: false,
                toggleTheme: false,
              },
            }}
          />
        </div>
      )
    })

    return Inner
  },
  {
    ssr: false,
    loading: () => (
      <div className="flex h-full min-h-[360px] items-center justify-center text-sm text-muted-foreground">
        Chargement de l&apos;éditeur…
      </div>
    ),
  }
)

function readSvgDimensions(svg: SVGSVGElement): { width: number; height: number } {
  const viewBox = svg.getAttribute("viewBox")
  if (viewBox) {
    const parts = viewBox.split(/\s+/).map(Number)
    if (parts.length === 4 && parts.every((n) => Number.isFinite(n))) {
      return {
        width: Math.max(24, Math.round(parts[2])),
        height: Math.max(24, Math.round(parts[3])),
      }
    }
  }
  const width = Number(svg.getAttribute("width"))
  const height = Number(svg.getAttribute("height"))
  if (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {
    return { width: Math.round(width), height: Math.round(height) }
  }
  return { width: 320, height: 240 }
}

function DocsExcalidrawEditorInner({
  drawScene,
  onReady,
}: {
  drawScene: string | null
  onReady: (api: ExcalidrawImperativeAPI) => void
}) {
  return <ExcalidrawEditor drawScene={drawScene} onReady={onReady} />
}

export const DocsExcalidrawEditor = memo(DocsExcalidrawEditorInner)

export function useDocsExcalidrawSave(api: ExcalidrawImperativeAPI | null) {
  const [saving, setSaving] = useState(false)

  const exportDrawing = useCallback(async (): Promise<DocsGraphicDrawSavePayload | null> => {
    if (!api) return null
    setSaving(true)
    try {
      const elements = api.getSceneElements()
      const appState = api.getAppState()
      const files = api.getFiles()
      const { exportToSvg, serializeAsJSON } = await import("@excalidraw/excalidraw")
      const drawScene = serializeAsJSON(elements, appState, files, "local")
      const svg = await exportToSvg({
        elements,
        appState,
        files,
        skipInliningFonts: true,
      })
      const svgString = new XMLSerializer().serializeToString(svg)
      const src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`
      const { width, height } = readSvgDimensions(svg)
      return { drawScene, src, width, height }
    } finally {
      setSaving(false)
    }
  }, [api])

  return { exportDrawing, saving }
}
