import type { Editor } from "@tiptap/react"
import { ensureMinimalTipTapDoc } from "@/lib/drive/richtext-content"

export type DocsApplyAction =
  | { action: "insert_text"; text: string }
  | { action: "replace_selection"; text: string }
  | { action: "append_paragraph"; text: string }
  | { action: "set_content"; document: Record<string, unknown> }

export function parseDocsApplyPayload(raw: unknown): DocsApplyAction | null {
  if (!raw || typeof raw !== "object") return null
  const obj = raw as Record<string, unknown>
  const action = obj.action
  if (action === "insert_text" && typeof obj.text === "string") {
    return { action, text: obj.text }
  }
  if (action === "replace_selection" && typeof obj.text === "string") {
    return { action, text: obj.text }
  }
  if (action === "append_paragraph" && typeof obj.text === "string") {
    return { action, text: obj.text }
  }
  if (action === "set_content" && obj.document && typeof obj.document === "object") {
    return {
      action,
      document: obj.document as Record<string, unknown>,
    }
  }
  return null
}

/** Extrait un bloc ```ulti-docs-apply depuis une réponse assistant. */
export function extractDocsApplyFromMarkdown(text: string): DocsApplyAction | null {
  const match = text.match(/```ulti-docs-apply\s*([\s\S]*?)```/i)
  if (!match?.[1]) return null
  try {
    return parseDocsApplyPayload(JSON.parse(match[1].trim()))
  } catch {
    return null
  }
}

export function applyDocsAction(editor: Editor, cmd: DocsApplyAction): boolean {
  if (!editor.isEditable) return false
  switch (cmd.action) {
    case "insert_text":
      return editor.chain().focus().insertContent(cmd.text).run()
    case "replace_selection":
      if (editor.state.selection.empty) {
        return editor.chain().focus().insertContent(cmd.text).run()
      }
      return editor.chain().focus().deleteSelection().insertContent(cmd.text).run()
    case "append_paragraph": {
      const blocks = cmd.text
        .split(/\n{2,}/)
        .map((p) => p.trim())
        .filter(Boolean)
        .map((p) => ({
          type: "paragraph",
          content: [{ type: "text", text: p }],
        }))
      if (blocks.length === 0) return false
      return editor.chain().focus().insertContentAt(editor.state.doc.content.size, blocks).run()
    }
    case "set_content": {
      const doc = ensureMinimalTipTapDoc(cmd.document)
      return editor.commands.setContent(doc)
    }
    default:
      return false
  }
}
