'use client'

import { Node, mergeAttributes } from '@tiptap/core'
import {
  ReactNodeViewRenderer,
  NodeViewWrapper,
  type NodeViewProps,
} from '@tiptap/react'
import type { Editor } from '@tiptap/core'
import { InteractiveDemoPlayer } from '@/components/interactive-demo/interactive-demo-player'
import {
  validateInteractiveDemo,
  type InteractiveDemoV1,
} from '@/lib/interactive-demo'
import attnresFixture from '@/lib/interactive-demo/fixtures/attnres.demo.json'
import { AlertCircle } from 'lucide-react'
import { useLanguage } from '@/lib/i18n'
import { useMemo } from 'react'

function InteractiveDemoView(props: NodeViewProps) {
  const { t } = useLanguage()
  const raw = props.node.attrs.demoJson as string

  const parsed = useMemo(() => {
    try {
      const data = JSON.parse(raw || '{}')
      return validateInteractiveDemo(data)
    } catch {
      return {
        ok: false as const,
        issues: [{ code: 'invalid_json', path: '', message: 'Invalid JSON' }],
      }
    }
  }, [raw])

  if (!parsed.ok) {
    return (
      <NodeViewWrapper
        className="interactive-demo-block my-4"
        data-drag-handle
        contentEditable={false}
      >
        <div className="rounded-xl border border-dashed border-destructive/40 bg-destructive/5 p-4 flex gap-3 text-sm">
          <AlertCircle className="h-5 w-5 text-destructive shrink-0" />
          <div>
            <p className="font-medium">
              {t('interactiveDemo.invalid') || 'Interactive demo invalide'}
            </p>
            <ul className="mt-1 text-muted-foreground list-disc list-inside">
              {parsed.issues.slice(0, 5).map((iss, i) => (
                <li key={i}>
                  {iss.path ? `${iss.path}: ` : ''}
                  {iss.message}
                </li>
              ))}
            </ul>
          </div>
        </div>
      </NodeViewWrapper>
    )
  }

  return (
    <NodeViewWrapper
      className="interactive-demo-block my-4"
      data-drag-handle
      contentEditable={false}
    >
      <InteractiveDemoPlayer demo={parsed.demo} mode="interactive" />
    </NodeViewWrapper>
  )
}

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

  addAttributes() {
    return {
      demoJson: {
        default: '{}',
        parseHTML: (el) => el.getAttribute('data-demo-json') || '{}',
        renderHTML: (attrs) => ({
          'data-demo-json': attrs.demoJson || '{}',
        }),
      },
    }
  },

  parseHTML() {
    return [{ tag: 'div[data-interactive-demo]' }]
  },

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

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

export function insertInteractiveDemoAtSelection(
  editor: Editor,
  demo?: InteractiveDemoV1
): boolean {
  const type = editor.schema.nodes.interactiveDemo
  if (!type) return false

  const payload = demo ?? (attnresFixture as InteractiveDemoV1)
  const check = validateInteractiveDemo(payload)
  // Prefer validated shape; if already-server-validated payload fails client Zod
  // (HMR drift), still insert so the block appears — NodeView shows issues if needed.
  const attrs = {
    demoJson: JSON.stringify(check.ok ? check.demo : payload),
  }
  const { empty, $from } = editor.state.selection
  const pos = empty ? $from.pos : editor.state.selection.from

  return editor
    .chain()
    .focus()
    .insertContentAt(pos, { type: 'interactiveDemo', attrs })
    .run()
}
