import { Extension } from "@tiptap/core"
import {
  buildParagraphSpacingStyle,
  DOCS_DEFAULT_PARAGRAPH_SPACING,
  parseLineHeightAttr,
  parseSpacingPt,
  readParagraphSpacingAttrs,
} from "@/lib/drive/docs-line-spacing"
import {
  setDocsCustomSpacing,
  setDocsLineHeight,
  toggleDocsKeepLinesTogether,
  toggleDocsKeepWithNext,
  toggleDocsPageBreakBefore,
  toggleDocsPreventWidowOrphan,
  toggleDocsSpaceAfter,
  toggleDocsSpaceBefore,
} from "@/lib/drive/docs-line-spacing-actions"

declare module "@tiptap/core" {
  interface Commands<ReturnType> {
    docsParagraphSpacing: {
      setDocsLineHeight: (lineHeight: number) => ReturnType
      setDocsCustomSpacing: (input: {
        lineHeight: number | null
        spaceBeforePt: number
        spaceAfterPt: number
      }) => ReturnType
      toggleDocsSpaceBefore: () => ReturnType
      toggleDocsSpaceAfter: () => ReturnType
      toggleDocsKeepWithNext: () => ReturnType
      toggleDocsKeepLinesTogether: () => ReturnType
      toggleDocsPreventWidowOrphan: () => ReturnType
      toggleDocsPageBreakBefore: () => ReturnType
    }
  }
}

function parseBoolAttr(raw: unknown): boolean {
  return raw === true || raw === "true" || raw === "1"
}

function spacingRenderHtml(attributes: Record<string, unknown>) {
  const spacing = readParagraphSpacingAttrs({ attrs: attributes })
  const style = buildParagraphSpacingStyle(spacing)
  const html: Record<string, string> = {}
  if (spacing.lineHeight != null) html["data-line-height"] = String(spacing.lineHeight)
  if (spacing.spaceBeforePt > 0) html["data-space-before-pt"] = String(spacing.spaceBeforePt)
  if (spacing.spaceAfterPt > 0) html["data-space-after-pt"] = String(spacing.spaceAfterPt)
  if (spacing.keepWithNext) html["data-keep-with-next"] = "true"
  if (spacing.keepLinesTogether) html["data-keep-lines-together"] = "true"
  if (spacing.preventWidowOrphan) html["data-prevent-widow-orphan"] = "true"
  if (spacing.pageBreakBefore) html["data-page-break-before"] = "true"
  if (style) html.style = style
  if (spacing.pageBreakBefore) {
    html.class = "docs-paragraph-spacing--page-break-before"
  }
  return html
}

export const DocsParagraphSpacing = Extension.create({
  name: "docsParagraphSpacing",

  addGlobalAttributes() {
    return [
      {
        types: ["paragraph", "heading"],
        attributes: {
          lineHeight: {
            default: DOCS_DEFAULT_PARAGRAPH_SPACING.lineHeight,
            parseHTML: (element) => {
              const raw = element.getAttribute("data-line-height")
              if (raw != null) return parseLineHeightAttr(raw)
              const style = (element as HTMLElement).style?.lineHeight
              if (!style) return null
              const numeric = Number.parseFloat(style)
              return Number.isFinite(numeric) ? numeric : null
            },
            renderHTML: (attributes) => spacingRenderHtml(attributes),
          },
          spaceBeforePt: {
            default: 0,
            parseHTML: (element) => parseSpacingPt(element.getAttribute("data-space-before-pt")),
            renderHTML: () => ({}),
          },
          spaceAfterPt: {
            default: 0,
            parseHTML: (element) => parseSpacingPt(element.getAttribute("data-space-after-pt")),
            renderHTML: () => ({}),
          },
          keepWithNext: {
            default: false,
            parseHTML: (element) => parseBoolAttr(element.getAttribute("data-keep-with-next")),
            renderHTML: () => ({}),
          },
          keepLinesTogether: {
            default: false,
            parseHTML: (element) => parseBoolAttr(element.getAttribute("data-keep-lines-together")),
            renderHTML: () => ({}),
          },
          preventWidowOrphan: {
            default: false,
            parseHTML: (element) => parseBoolAttr(element.getAttribute("data-prevent-widow-orphan")),
            renderHTML: () => ({}),
          },
          pageBreakBefore: {
            default: false,
            parseHTML: (element) => parseBoolAttr(element.getAttribute("data-page-break-before")),
            renderHTML: () => ({}),
          },
        },
      },
    ]
  },

  addCommands() {
    return {
      setDocsLineHeight:
        (lineHeight: number) =>
        ({ editor }) =>
          setDocsLineHeight(editor, lineHeight),
      setDocsCustomSpacing:
        (input) =>
        ({ editor }) =>
          setDocsCustomSpacing(editor, input),
      toggleDocsSpaceBefore:
        () =>
        ({ editor }) =>
          toggleDocsSpaceBefore(editor),
      toggleDocsSpaceAfter:
        () =>
        ({ editor }) =>
          toggleDocsSpaceAfter(editor),
      toggleDocsKeepWithNext:
        () =>
        ({ editor }) =>
          toggleDocsKeepWithNext(editor),
      toggleDocsKeepLinesTogether:
        () =>
        ({ editor }) =>
          toggleDocsKeepLinesTogether(editor),
      toggleDocsPreventWidowOrphan:
        () =>
        ({ editor }) =>
          toggleDocsPreventWidowOrphan(editor),
      toggleDocsPageBreakBefore:
        () =>
        ({ editor }) =>
          toggleDocsPageBreakBefore(editor),
    }
  },
})
