'use client'

import { Node, mergeAttributes } from '@tiptap/core'
import { ReactNodeViewRenderer, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'
import { useEffect, useRef, useState, useCallback } from 'react'
import { Zap, AlertCircle, Unlink, ArrowRight, Trash2 } from 'lucide-react'
import { useLanguage } from '@/lib/i18n'
import { NOTE_REQUEST_SAVE_EVENT } from '@/lib/note-change-sync'
import { openNotePeek } from '@/lib/note-peek-sync'

declare module '@tiptap/core' {
  interface Storage {
    liveBlock: {
      hostNoteId: string | null
    }
  }
}

// ---------------------------------------------------------------------------
// LiveBlock Node View
// ---------------------------------------------------------------------------

function LiveBlockView({ node, updateAttributes, deleteNode, editor, getPos }: NodeViewProps) {
  const { t } = useLanguage()
  const { sourceNoteId, blockId, snapshotContent, sourceNoteTitle } = node.attrs
  const [localContent, setLocalContent] = useState(snapshotContent || '')
  const [isDeleted, setIsDeleted] = useState(false)
  const [isOffline, setIsOffline] = useState(false)
  const [pulse, setPulse] = useState(false)
  const pulseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  const requestSave = useCallback(() => {
    const hostNoteId = editor.storage.liveBlock?.hostNoteId
    if (hostNoteId) {
      window.dispatchEvent(new CustomEvent(NOTE_REQUEST_SAVE_EVENT, {
        detail: { noteId: hostNoteId, reason: 'live-block-mutation' },
      }))
    }
  }, [editor])

  // Fetch current block status on mount
  useEffect(() => {
    if (!sourceNoteId || !blockId) return
    fetch(`/api/blocks/${encodeURIComponent(blockId)}/status?sourceNoteId=${sourceNoteId}`)
      .then(r => r.json())
      .then((data: { exists: boolean; content: string; sourceNoteTitle: string }) => {
        if (!data.exists) {
          if (snapshotContent?.trim()) {
            setLocalContent(snapshotContent)
            return
          }
          setIsDeleted(true)
        } else {
          setLocalContent(data.content)
          updateAttributes({ snapshotContent: data.content, sourceNoteTitle: data.sourceNoteTitle })
        }
      })
      .catch(() => setIsOffline(true))
  }, [sourceNoteId, blockId, snapshotContent, updateAttributes])

  // Listen for real-time block update events
  useEffect(() => {
    const handleBlockUpdate = (e: CustomEvent) => {
      if (e.detail?.blockId !== blockId) return
      setLocalContent(e.detail.content)
      updateAttributes({ snapshotContent: e.detail.content })
      setPulse(true)
      if (pulseTimerRef.current) clearTimeout(pulseTimerRef.current)
      pulseTimerRef.current = setTimeout(() => setPulse(false), 1200)
    }
    const handleBlockDeleted = (e: CustomEvent) => {
      if (e.detail?.blockId !== blockId) return
      setIsDeleted(true)
    }

    window.addEventListener('live-block:update', handleBlockUpdate as EventListener)
    window.addEventListener('live-block:deleted', handleBlockDeleted as EventListener)
    return () => {
      window.removeEventListener('live-block:update', handleBlockUpdate as EventListener)
      window.removeEventListener('live-block:deleted', handleBlockDeleted as EventListener)
      if (pulseTimerRef.current) clearTimeout(pulseTimerRef.current)
    }
  }, [blockId, updateAttributes])

  /** Convertit le bloc live en paragraphe local (conserve le texte affiché). */
  const handleDetach = useCallback(() => {
    const pos = getPos()
    if (typeof pos !== 'number') return
    const currentNode = editor.state.doc.nodeAt(pos)
    if (!currentNode) return

    const text = localContent.trim()
    const paragraph = editor.state.schema.nodes.paragraph.create(
      null,
      text ? editor.state.schema.text(text) : undefined,
    )
    editor.view.dispatch(editor.state.tr.replaceWith(pos, pos + currentNode.nodeSize, paragraph))
    editor.commands.focus()
    requestSave()
  }, [editor, getPos, localContent, requestSave])

  const handleRemove = useCallback(() => {
    deleteNode()
    requestSave()
  }, [deleteNode, requestSave])

  const handleOpenSource = useCallback((event: React.MouseEvent) => {
    event.preventDefault()
    event.stopPropagation()
    openNotePeek({ noteId: sourceNoteId, blockId: blockId || undefined })
  }, [sourceNoteId, blockId])

  const borderClass = isDeleted
    ? 'border-l-rose-500 border-y-rose-200 border-r-rose-200 bg-rose-50/20 dark:border-l-red-700 dark:border-y-red-900/40 dark:border-r-red-900/40 dark:bg-red-950/5'
    : isOffline
    ? 'border-l-amber-500 border-y-amber-200 border-r-amber-200 bg-amber-50/10 dark:border-l-amber-600 dark:border-y-amber-800/40 dark:border-r-amber-800/40'
    : pulse
    ? 'border-l-blue-500 border-y-blue-300 border-r-blue-300 bg-blue-50/20 shadow-md shadow-blue-500/15 dark:bg-blue-950/10'
    : 'border-l-blue-500 border-y-[#E8E6E3] border-r-[#E8E6E3] bg-blue-50/5 dark:border-y-zinc-800 dark:border-r-zinc-800 dark:bg-blue-950/5'

  const headerTitle = isDeleted
    ? t('liveBlock.sourceDisconnected')
    : (sourceNoteTitle || t('liveBlock.connectedNote'))

  const actionButtonClass =
    'text-[9.5px] font-bold flex items-center gap-1 transition-all shrink-0'

  return (
    <NodeViewWrapper>
      <div className="group/liveblock my-4 not-prose">
        <div className={`w-full rounded-xl border-l-[3px] border-y border-r transition-all duration-300 overflow-hidden ${borderClass}`}>
          {/* Header */}
          <div className="px-4 py-1.5 flex items-center justify-between bg-black/[0.015] dark:bg-white/[0.01] border-b border-black/[0.03] dark:border-white/[0.02]">
            <div className="flex items-center gap-2 min-w-0">
              {isDeleted ? (
                <AlertCircle size={10} className="text-rose-500 shrink-0" />
              ) : (
                <Zap size={10} className={`shrink-0 ${isOffline ? 'text-amber-500' : 'text-blue-500 fill-blue-500/20'}`} />
              )}
              <span className="text-[10px] font-sans font-medium text-[var(--color-concrete)] hover:text-[var(--color-ink)] transition-colors cursor-default max-w-[200px] truncate">
                {headerTitle}
              </span>
              {isDeleted ? (
                <span className="bg-rose-500/10 text-rose-600 dark:text-rose-400 font-bold px-1.5 rounded text-[8px] uppercase tracking-wider">
                  {t('liveBlock.statusDisconnected')}
                </span>
              ) : isOffline ? (
                <span className="bg-amber-500/10 text-amber-600 dark:text-amber-400 font-bold px-1.5 rounded text-[8px] uppercase tracking-wider">
                  {t('liveBlock.statusOffline')}
                </span>
              ) : (
                <span className="bg-blue-500/10 text-blue-600 dark:text-blue-400 font-bold px-1.5 rounded text-[8px] uppercase tracking-wider animate-pulse">
                  {t('liveBlock.statusLive')}
                </span>
              )}
            </div>
            <div
              className={`flex items-center gap-2 shrink-0 ${isDeleted ? '' : 'opacity-0 group-hover/liveblock:opacity-100'} transition-opacity`}
            >
              <button
                type="button"
                onClick={handleDetach}
                title={t('liveBlock.detachHelp')}
                className={`${actionButtonClass} ${
                  isDeleted
                    ? 'text-rose-600 hover:text-rose-500 dark:text-rose-400 hover:underline'
                    : 'text-[var(--color-concrete)] hover:text-[var(--color-ink)] dark:hover:text-[var(--color-dark-ink)]'
                }`}
                contentEditable={false}
              >
                <Unlink size={10} />
                {t('liveBlock.detachLink')}
              </button>
              {!isDeleted && (
                <button
                  type="button"
                  onClick={handleOpenSource}
                  className={`${actionButtonClass} text-blue-600 dark:text-blue-400 hover:underline`}
                  contentEditable={false}
                >
                  {t('liveBlock.openSource')} <ArrowRight size={10} />
                </button>
              )}
              <button
                type="button"
                onClick={handleRemove}
                title={t('liveBlock.removeBlock')}
                className={`${actionButtonClass} text-rose-600/80 hover:text-rose-600 dark:text-rose-400/80 dark:hover:text-rose-400`}
                contentEditable={false}
              >
                <Trash2 size={10} />
              </button>
            </div>
          </div>
          {/* Content */}
          <div className="px-4 py-3 bg-blue-500/[0.015] dark:bg-blue-500/[0.005]">
            <p
              className="text-sm leading-relaxed text-[var(--color-ink)] opacity-80 dark:text-[var(--color-dark-ink)] font-sans whitespace-pre-wrap"
              contentEditable={false}
            >
              {localContent || t('liveBlock.emptyContent')}
            </p>
          </div>
        </div>
      </div>
    </NodeViewWrapper>
  )
}

// ---------------------------------------------------------------------------
// TipTap Node Definition
// ---------------------------------------------------------------------------

export const LiveBlockExtension = Node.create({
  name: 'liveBlock',
  group: 'block',
  atom: true,
  draggable: true,
  selectable: true,

  addStorage() {
    return {
      hostNoteId: null as string | null,
    }
  },

  addAttributes() {
    return {
      sourceNoteId: { default: '' },
      blockId: { default: '' },
      snapshotContent: { default: '' },
      sourceNoteTitle: { default: '' },
    }
  },

  parseHTML() {
    return [{ tag: 'div[data-live-block]' }]
  },

  renderHTML({ HTMLAttributes }) {
    return ['div', mergeAttributes(HTMLAttributes, { 'data-live-block': 'true' })]
  },

  addNodeView() {
    return ReactNodeViewRenderer(LiveBlockView)
  },
})
