import type { Editor } from "@tiptap/react"
import type { Node as ProseMirrorNode } from "@tiptap/pm/model"
import { getDocsBlockTargets } from "@/lib/drive/docs-block-targets"
import {
  clampIndentLevel,
  nextIndentLevel,
} from "@/lib/drive/docs-indent"

function applyBlockIndentDelta(editor: Editor, delta: number): boolean {
  const { state } = editor
  const targets = getDocsBlockTargets(state.doc, state.selection.from, state.selection.to)
  if (targets.length === 0) return false

  let tr = state.tr
  let changed = false

  for (const { pos, node } of targets) {
    const current = clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0)
    const next = nextIndentLevel(current, delta)
    if (next === current) continue
    tr = tr.setNodeMarkup(pos, undefined, { ...node.attrs, indentLevel: next })
    changed = true
  }

  if (!changed) return false
  editor.view.dispatch(tr.scrollIntoView())
  return true
}

export function increaseDocsIndent(editor: Editor | null): boolean {
  if (!editor || editor.isDestroyed) return false

  if (editor.isActive("taskItem")) {
    return editor.can().sinkListItem("taskItem")
      ? editor.chain().focus().sinkListItem("taskItem").run()
      : false
  }

  if (editor.isActive("listItem")) {
    return editor.can().sinkListItem("listItem")
      ? editor.chain().focus().sinkListItem("listItem").run()
      : false
  }

  return applyBlockIndentDelta(editor, 1)
}

export function decreaseDocsIndent(editor: Editor | null): boolean {
  if (!editor || editor.isDestroyed) return false

  if (editor.isActive("taskItem")) {
    return editor.can().liftListItem("taskItem")
      ? editor.chain().focus().liftListItem("taskItem").run()
      : false
  }

  if (editor.isActive("listItem")) {
    return editor.can().liftListItem("listItem")
      ? editor.chain().focus().liftListItem("listItem").run()
      : false
  }

  return applyBlockIndentDelta(editor, -1)
}

export function canIncreaseDocsIndent(editor: Editor | null): boolean {
  if (!editor || editor.isDestroyed) return false
  if (editor.isActive("taskItem")) return editor.can().sinkListItem("taskItem")
  if (editor.isActive("listItem")) return editor.can().sinkListItem("listItem")
  return getDocsBlockTargets(
    editor.state.doc,
    editor.state.selection.from,
    editor.state.selection.to
  ).some(
    ({ node }) =>
      nextIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0, 1) !==
      clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0)
  )
}

export function canDecreaseDocsIndent(editor: Editor | null): boolean {
  if (!editor || editor.isDestroyed) return false
  if (editor.isActive("taskItem")) return editor.can().liftListItem("taskItem")
  if (editor.isActive("listItem")) return editor.can().liftListItem("listItem")
  return getDocsBlockTargets(
    editor.state.doc,
    editor.state.selection.from,
    editor.state.selection.to
  ).some(({ node }) => clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0) > 0)
}
