import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import Placeholder from '@tiptap/extension-placeholder'
import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
import Link from '@tiptap/extension-link'
import Image from '@tiptap/extension-image'
import Table from '@tiptap/extension-table'
import TableRow from '@tiptap/extension-table-row'
import TableCell from '@tiptap/extension-table-cell'
import TableHeader from '@tiptap/extension-table-header'
import type { Editor as TiptapEditor } from '@tiptap/core'
import { useEffect, forwardRef, useImperativeHandle } from 'preact/compat'
import { serializeDocToMarkdown, parseMarkdownToHtml } from './markdown-bridge'
import type { ToolbarCommand } from './Toolbar'

export interface EditorProps {
  markdown: string
  placeholder: string
  onChange: (markdown: string) => void
  onActiveMarksChange: (active: Partial<Record<ToolbarCommand, boolean>>) => void
}

export interface EditorHandle {
  runCommand: (kind: ToolbarCommand) => void
}

export const Editor = forwardRef<EditorHandle, EditorProps>(function Editor(
  { markdown, placeholder, onChange, onActiveMarksChange },
  ref,
) {
  const editor = useEditor({
    extensions: [
      StarterKit.configure({ heading: { levels: [1, 2, 3] } }),
      Underline,
      Placeholder.configure({ placeholder }),
      TaskList,
      TaskItem.configure({ nested: true }),
      Link.configure({
        openOnClick: false,
        autolink: true,
        linkOnPaste: true,
        protocols: ['http', 'https', 'mailto', 'tel'],
        HTMLAttributes: { rel: 'noopener noreferrer', target: '_blank' },
      }),
      Image,
      Table.configure({ resizable: false }),
      TableRow,
      TableCell,
      TableHeader,
    ],
    content: parseMarkdownToHtml(markdown),
    onUpdate: ({ editor }) => {
      onChange(serializeDocToMarkdown(editor))
      onActiveMarksChange(readActiveMarks(editor))
    },
    onSelectionUpdate: ({ editor }) => onActiveMarksChange(readActiveMarks(editor)),
  })

  useEffect(() => {
    if (!editor) return
    const current = serializeDocToMarkdown(editor)
    if (markdown !== current) {
      editor.commands.setContent(parseMarkdownToHtml(markdown), false)
    }
  }, [editor, markdown])

  useImperativeHandle(ref, () => ({
    runCommand(kind) {
      if (!editor) return
      const chain = editor.chain().focus()
      switch (kind) {
        case 'bold':           chain.toggleBold().run(); break
        case 'italic':         chain.toggleItalic().run(); break
        case 'underline':      chain.toggleUnderline().run(); break
        case 'bulletList':     chain.toggleBulletList().run(); break
        case 'orderedList':    chain.toggleOrderedList().run(); break
        case 'taskList':       chain.toggleTaskList().run(); break
        case 'heading':        chain.toggleHeading({ level: 2 }).run(); break
        case 'blockquote':     chain.toggleBlockquote().run(); break
        case 'codeBlock':      chain.toggleCodeBlock().run(); break
        case 'horizontalRule': chain.setHorizontalRule().run(); break
        case 'link':           toggleLink(editor); break
      }
    },
  }), [editor])

  return (
    <div class="editor-wrapper">
      <EditorContent editor={editor} />
    </div>
  )
})

function toggleLink(editor: TiptapEditor) {
  if (editor.isActive('link')) {
    editor.chain().focus().unsetLink().run()
    return
  }
  const previous = (editor.getAttributes('link').href as string | undefined) ?? ''
  const url = window.prompt('Link URL', previous)
  if (url === null) return
  const trimmed = url.trim()
  if (!trimmed) {
    editor.chain().focus().unsetLink().run()
    return
  }
  if (!/^(?:https?:|mailto:|tel:)/i.test(trimmed)) {
    window.alert('Link must start with http://, https://, mailto:, or tel:')
    return
  }
  editor.chain().focus().extendMarkRange('link').setLink({ href: trimmed }).run()
}

function readActiveMarks(editor: TiptapEditor): Partial<Record<ToolbarCommand, boolean>> {
  return {
    bold:        editor.isActive('bold'),
    italic:      editor.isActive('italic'),
    underline:   editor.isActive('underline'),
    bulletList:  editor.isActive('bulletList'),
    orderedList: editor.isActive('orderedList'),
    taskList:    editor.isActive('taskList'),
    heading:     editor.isActive('heading'),
    blockquote:  editor.isActive('blockquote'),
    codeBlock:   editor.isActive('codeBlock'),
    link:        editor.isActive('link'),
  }
}
