'use client'

import dynamic from 'next/dynamic'
import { useState, useEffect, useRef, useMemo } from 'react'
import { toast } from 'sonner'
import { Download, Presentation } 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'

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

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

type PptxPayload = { type: string; filename: string; base64: string; slideCount?: number; theme?: string }

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

export function CanvasBoard({ initialData, canvasId, name }: CanvasBoardProps) {
  const [isDarkMode, setIsDarkMode] = useState(false)
  const [saveStatus, setSaveStatus] = useState<'saved' | 'saving' | 'error'>('saved')
  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 })
        await fetch('/api/canvas', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ id: canvasId || null, name, data: snapshot })
        })
        setSaveStatus('saved')
      } catch (e) {
        console.error('[CanvasBoard] Save failure:', e)
        setSaveStatus('error')
      }
    }, 2000)
  }

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

  const excalKey = canvasId ? `excal-${canvasId}` : '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>
  )
}
