'use client'

import dynamic from 'next/dynamic'
import { useState, useEffect, useRef, useMemo } from 'react'
import { useRouter } from 'next/navigation'
import { toast } from 'sonner'
import { Download, Presentation, ExternalLink, Maximize2, ChevronLeft, ChevronRight } from 'lucide-react'
import type { ExcalidrawElement } from '@excalidraw/excalidraw/element/types'
import type { AppState, BinaryFiles } from '@excalidraw/excalidraw/types'
import type { ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types'
import '@excalidraw/excalidraw/index.css'
import type { PresentationSpec } from '@/lib/types/presentation'

const Excalidraw = dynamic(
  async () => (await import('@excalidraw/excalidraw')).Excalidraw,
  { ssr: false }
)

const SlidesRenderer = dynamic(
  () => import('./slides-renderer').then(m => ({ default: m.SlidesRenderer })),
  { ssr: false, loading: () => <div className="absolute inset-0 flex items-center justify-center bg-zinc-950 text-white/40 text-sm">Chargement des slides…</div> }
)

interface CanvasBoardProps {
  initialData?: string
  canvasId?: string
  name: string
}

type PptxPayload = { type: string; filename: string; base64: string; slideCount?: number; theme?: string }
type SlidesPayload = { type: 'slides'; html: string; title: string; theme?: string; style?: string; slideCount?: number; spec?: PresentationSpec }

function parseCanvasScene(initialData?: string): {
  slides: SlidesPayload | null
  pptx: PptxPayload | null
  elements: readonly ExcalidrawElement[]
  files: BinaryFiles
} {
  if (!initialData) {
    return { slides: null, pptx: null, elements: [], files: {} }
  }
  try {
    const parsed = JSON.parse(initialData)
    if (parsed && parsed.type === 'slides' && parsed.html) {
      return { slides: parsed as SlidesPayload, pptx: null, elements: [], files: {} }
    }
    if (parsed && parsed.type === 'pptx' && parsed.base64) {
      return { slides: null, pptx: parsed as PptxPayload, elements: [], files: {} }
    }
    if (parsed && Array.isArray(parsed)) {
      return { slides: null, pptx: null, elements: parsed as ExcalidrawElement[], files: {} }
    }
    if (parsed && parsed.elements) {
      const files: BinaryFiles =
        parsed.files && typeof parsed.files === 'object' ? parsed.files : {}
      return { slides: null, pptx: null, elements: parsed.elements as readonly ExcalidrawElement[], files }
    }
  } catch (e) {
    console.error('[CanvasBoard] Failed to parse canvas data:', e)
  }
  return { slides: null, pptx: null, elements: [], files: {} }
}

function PptxViewer({ data, name }: { data: PptxPayload; name: string }) {
  const handleDownload = () => {
    try {
      const byteCharacters = atob(data.base64)
      const byteNumbers = new Array(byteCharacters.length)
      for (let i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i)
      }
      const byteArray = new Uint8Array(byteNumbers)
      const blob = new Blob([byteArray], {
        type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
      })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = data.filename || `${name}.pptx`
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)
    } catch (e) {
      console.error('[PptxViewer] Download failed:', e)
      toast.error('Failed to download presentation')
    }
  }

  return (
    <div className="absolute inset-0 h-full w-full flex flex-col items-center justify-center bg-white dark:bg-zinc-900">
      <div className="flex flex-col items-center gap-6 p-8">
        <div className="p-4 rounded-2xl bg-primary/10">
          <Presentation className="w-16 h-16 text-primary" />
        </div>
        <div className="text-center">
          <h2 className="text-xl font-semibold text-foreground mb-1">{name}</h2>
          <p className="text-sm text-muted-foreground">
            PowerPoint Presentation
            {data.slideCount ? ` • ${data.slideCount} slides` : ''}
            {data.theme ? ` • ${data.theme} theme` : ''}
          </p>
        </div>
        <button
          onClick={handleDownload}
          className="flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-xl hover:bg-primary/90 transition-colors font-medium shadow-sm"
        >
          <Download className="w-5 h-5" />
          Download .pptx
        </button>
        <p className="text-xs text-muted-foreground max-w-sm text-center">
          This file can be opened in Microsoft PowerPoint, Google Slides, or Keynote.
        </p>
      </div>
    </div>
  )
}

function SlidesViewer({ data, name, canvasId }: { data: SlidesPayload; name: string; canvasId?: string | null }) {
  const iframeRef = useRef<HTMLIFrameElement>(null)
  const [currentSlide, setCurrentSlide] = useState(1)
  const [isLoaded, setIsLoaded] = useState(!!data.spec) // spec → React renderer, no iframe loading
  const totalSlides = data.slideCount || 1

  // Hide the global AI floating button while slides are displayed
  useEffect(() => {
    window.dispatchEvent(new CustomEvent('contextual-ai-visibility', { detail: true }))
    return () => {
      window.dispatchEvent(new CustomEvent('contextual-ai-visibility', { detail: false }))
    }
  }, [])

  // Listen for slide-change events from the iframe via postMessage
  useEffect(() => {
    const handler = (e: MessageEvent) => {
      if (e.data?.type === 'slideChange' && typeof e.data.current === 'number') {
        setCurrentSlide(e.data.current)
      }
    }
    window.addEventListener('message', handler)
    return () => window.removeEventListener('message', handler)
  }, [])

  const navigate = (dir: number) => {
    const iframe = iframeRef.current
    if (!iframe) return
    // Direct contentWindow access (works with allow-same-origin)
    try {
      const win = iframe.contentWindow as any
      if (typeof win?.changeSlide === 'function') {
        win.changeSlide(dir)
        return
      }
    } catch (_) {}
    // Fallback: postMessage
    iframe.contentWindow?.postMessage({ type: 'navigate', dir }, '*')
  }

  const openFullscreen = () => {
    const blob = new Blob([data.html], { type: 'text/html' })
    const url = URL.createObjectURL(blob)
    window.open(url, '_blank')
    setTimeout(() => URL.revokeObjectURL(url), 10000)
  }

  const downloadHtml = () => {
    const blob = new Blob([data.html], { type: 'text/html' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `${name.replace(/[^a-z0-9]/gi, '-').toLowerCase() || 'presentation'}.html`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    setTimeout(() => URL.revokeObjectURL(url), 5000)
  }

  return (
    <div className="absolute inset-0 flex flex-col bg-zinc-950">
      {/* Toolbar */}
      <div className="shrink-0 h-11 flex items-center justify-between px-4 bg-zinc-900/80 border-b border-white/10 backdrop-blur-sm z-10">
        <div className="flex items-center gap-2.5 text-white/70 min-w-0">
          <Presentation className="w-4 h-4 shrink-0 text-white/50" />
          <span className="text-sm font-medium truncate">{name}</span>
          {totalSlides > 1 && (
            <span className="text-xs bg-white/10 px-2 py-0.5 rounded-full shrink-0 tabular-nums">
              {currentSlide} / {totalSlides}
            </span>
          )}
        </div>
        <div className="flex items-center gap-2">
          {canvasId && (
            <a
              href={`/api/canvas/slides/pptx?id=${canvasId}`}
              download
              className="flex items-center gap-1.5 px-3 py-1.5 bg-white/10 hover:bg-white/20 rounded-lg text-white/70 hover:text-white text-xs font-medium transition-all"
              title="Exporter en PowerPoint"
            >
              <Download className="w-3.5 h-3.5" />
              Export PPTX
            </a>
          )}
          <button
            onClick={downloadHtml}
            className="flex items-center gap-1.5 px-3 py-1.5 bg-white/10 hover:bg-white/20 rounded-lg text-white/70 hover:text-white text-xs font-medium transition-all"
            title="Télécharger le HTML"
          >
            <Download className="w-3.5 h-3.5" />
            Export HTML
          </button>
          <button
            onClick={openFullscreen}
            className="flex items-center gap-1.5 px-3 py-1.5 bg-white/10 hover:bg-white/20 rounded-lg text-white/70 hover:text-white text-xs font-medium transition-all"
            title="Ouvrir en plein écran"
          >
            <Maximize2 className="w-3.5 h-3.5" />
            Plein écran
          </button>
        </div>
      </div>
      {/* Slides: React renderer (legacy spec) or iframe (new HTML) */}
      <div className="flex-1 relative overflow-hidden group">
        {data.spec ? (
          <SlidesRenderer spec={data.spec} />
        ) : (
          <>
            {/* Loading overlay — visible until iframe fires onLoad */}
            {!isLoaded && (
              <div className="absolute inset-0 z-20 flex flex-col items-center justify-center bg-zinc-950 gap-3">
                <div className="w-8 h-8 rounded-full border-2 border-white/10 border-t-white/60 animate-spin" />
                <span className="text-xs text-white/30">Chargement de la présentation…</span>
              </div>
            )}
            <iframe
              ref={iframeRef}
              srcDoc={data.html}
              className="absolute inset-0 w-full h-full border-0"
              sandbox="allow-scripts allow-same-origin allow-popups allow-forms"
              title={name}
              allow="fullscreen"
              onLoad={() => setIsLoaded(true)}
            />
            {/* Prev button */}
            <button
              onClick={() => navigate(-1)}
              className="absolute left-2 top-1/2 -translate-y-1/2 z-10 w-9 h-9 flex items-center justify-center rounded-full bg-black/40 hover:bg-black/70 backdrop-blur-sm border border-white/10 text-white/40 hover:text-white transition-all opacity-0 group-hover:opacity-100"
              aria-label="Slide précédent"
            >
              <ChevronLeft className="w-5 h-5" />
            </button>
            {/* Next button */}
            <button
              onClick={() => navigate(1)}
              className="absolute right-2 top-1/2 -translate-y-1/2 z-10 w-9 h-9 flex items-center justify-center rounded-full bg-black/40 hover:bg-black/70 backdrop-blur-sm border border-white/10 text-white/40 hover:text-white transition-all opacity-0 group-hover:opacity-100"
              aria-label="Slide suivant"
            >
              <ChevronRight className="w-5 h-5" />
            </button>
          </>
        )}
      </div>
    </div>
  )
}

export function CanvasBoard({ initialData, canvasId, name }: CanvasBoardProps) {
  const [isDarkMode, setIsDarkMode] = useState(false)
  const [saveStatus, setSaveStatus] = useState<'saved' | 'saving' | 'error'>('saved')
  const [localId, setLocalId] = useState<string | null>(canvasId || null)
  const router = useRouter()
  const saveTimeoutRef = useRef<NodeJS.Timeout | null>(null)
  const excalidrawAPIRef = useRef<ExcalidrawImperativeAPI | null>(null)
  const filesRef = useRef<BinaryFiles>({})

  const scene = useMemo(
    () => parseCanvasScene(initialData),
    [canvasId, initialData]
  )

  useEffect(() => {
    filesRef.current = scene.files
  }, [scene])

  useEffect(() => {
    const checkDarkMode = () => {
      const isDark = document.documentElement.classList.contains('dark')
      setIsDarkMode(isDark)
    }

    checkDarkMode()

    const observer = new MutationObserver(checkDarkMode)
    observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })

    return () => observer.disconnect()
  }, [])

  const handleChange = (
    excalidrawElements: readonly ExcalidrawElement[],
    _appState: AppState,
    files: BinaryFiles
  ) => {
    if (files) filesRef.current = files

    if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)

    setSaveStatus('saving')
    saveTimeoutRef.current = setTimeout(async () => {
      try {
        const snapshot = JSON.stringify({ elements: excalidrawElements, files: filesRef.current })
        const res = await fetch('/api/canvas', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ id: localId || null, name, data: snapshot })
        })
        const data = await res.json()
        
        if (data.success && data.canvas?.id) {
          if (!localId) {
            setLocalId(data.canvas.id)
            router.replace(`/lab?id=${data.canvas.id}`, { scroll: false })
          }
          setSaveStatus('saved')
        } else {
          throw new Error(data.error || 'Failed to save')
        }
      } catch (e) {
        console.error('[CanvasBoard] Save failure:', e)
        setSaveStatus('error')
      }
    }, 2000)
  }

  if (scene.slides) {
    return <SlidesViewer data={scene.slides} name={name} canvasId={localId} />
  }

  if (scene.pptx) {
    return <PptxViewer data={scene.pptx} name={name} />
  }

  const excalKey = localId ? `excal-${localId}` : 'excal-new'

  return (
    <div className="absolute inset-0 h-full w-full bg-slate-50 dark:bg-[#121212]" dir="ltr">
      <Excalidraw
        key={excalKey}
        excalidrawAPI={(api) => { excalidrawAPIRef.current = api }}
        initialData={{ elements: scene.elements, files: scene.files }}
        theme={isDarkMode ? 'dark' : 'light'}
        onChange={handleChange}
        UIOptions={{
          canvasActions: {
            loadScene: true,
            saveToActiveFile: false,
            clearCanvas: true,
          }
        }}
        validateEmbeddable={false}
      />
    </div>
  )
}
