import assert from "node:assert/strict"
import { describe, it } from "node:test"
import { Schema } from "@tiptap/pm/model"
import { EditorState } from "@tiptap/pm/state"
import { childPosAtIndex } from "./docs-graphic-flow-move.ts"

const schema = new Schema({
  nodes: {
    doc: { content: "block+" },
    paragraph: {
      group: "block",
      content: "text*",
      toDOM: () => ["p", 0] as const,
      parseDOM: [{ tag: "p" }],
    },
    docsGraphic: {
      group: "block",
      atom: true,
      attrs: { alt: { default: "" } },
      toDOM: () => ["div", { "data-type": "docs-graphic" }] as const,
      parseDOM: [{ tag: 'div[data-type="docs-graphic"]' }],
    },
    text: { group: "inline" },
  },
})

function buildDoc(...blocks: PMBlock[]) {
  return schema.node("doc", null, blocks)
}

type PMBlock = ReturnType<typeof schema.node>

describe("docs-graphic-flow-move", () => {
  it("childPosAtIndex resolves sibling positions in the document", () => {
    const p0 = schema.node("paragraph", null, [schema.text("a")])
    const g = schema.node("docsGraphic", { alt: "img" })
    const p1 = schema.node("paragraph", null, [schema.text("b")])
    const doc = buildDoc(p0, g, p1)

    const graphicPos = p0.nodeSize
    const $pos = doc.resolve(graphicPos)
    assert.equal($pos.index($pos.depth), 1)
    assert.equal(childPosAtIndex($pos, 0), 0)
    assert.equal(childPosAtIndex($pos, 1), p0.nodeSize)
    assert.equal(childPosAtIndex($pos, 2), p0.nodeSize + g.nodeSize)
    assert.equal(childPosAtIndex($pos, 3), p0.nodeSize + g.nodeSize + p1.nodeSize)
  })

  it("moves a block graphic up by swapping with the previous sibling", () => {
    const p0 = schema.node("paragraph", null, [schema.text("a")])
    const g = schema.node("docsGraphic", { alt: "img" })
    const p1 = schema.node("paragraph", null, [schema.text("b")])
    const doc = buildDoc(p0, g, p1)
    const state = EditorState.create({ doc })
    const graphicPos = p0.nodeSize

    const tr = state.tr
    const $pos = state.doc.resolve(graphicPos)
    const insertPos = childPosAtIndex($pos, $pos.index($pos.depth) - 1)
    tr.delete(graphicPos, graphicPos + g.nodeSize)
    tr.insert(tr.mapping.map(insertPos), g)

    assert.equal(tr.doc.child(0).type.name, "docsGraphic")
    assert.equal(tr.doc.child(1).type.name, "paragraph")
    assert.equal(tr.doc.child(2).type.name, "paragraph")
  })

  it("moves a block graphic down by swapping with the next sibling", () => {
    const p0 = schema.node("paragraph", null, [schema.text("a")])
    const g = schema.node("docsGraphic", { alt: "img" })
    const p1 = schema.node("paragraph", null, [schema.text("b")])
    const doc = buildDoc(p0, g, p1)
    const state = EditorState.create({ doc })
    const graphicPos = p0.nodeSize

    const tr = state.tr
    const $pos = state.doc.resolve(graphicPos)
    const insertPos = childPosAtIndex($pos, $pos.index($pos.depth) + 2)
    tr.delete(graphicPos, graphicPos + g.nodeSize)
    tr.insert(tr.mapping.map(insertPos), g)

    assert.equal(tr.doc.child(0).type.name, "paragraph")
    assert.equal(tr.doc.child(1).type.name, "paragraph")
    assert.equal(tr.doc.child(2).type.name, "docsGraphic")
  })
})
