import { DOMParser } from 'prosemirror-model'
import { Selection, Transaction } from 'prosemirror-state'
import { ReplaceStep, ReplaceAroundStep } from 'prosemirror-transform'
import { Command } from '../Editor'
import elementFromString from '../utils/elementFromString'

type InsertHTMLCommand = (value: string) => Command

declare module '../Editor' {
  interface Commands {
    insertHTML: InsertHTMLCommand,
  }
}

// TODO: move to utils
// https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466
function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number) {
  const last = tr.steps.length - 1
  if (last < startLen) return
  const step = tr.steps[last]
  if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) return
  const map = tr.mapping.maps[last]
  let end = 0
  map.forEach((_from, _to, _newFrom, newTo) => { if (end === 0) end = newTo })
  tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias))
}

export const insertHTML: InsertHTMLCommand = value => ({ tr, state }) => {
  const { selection } = tr
  const element = elementFromString(value)
  const slice = DOMParser.fromSchema(state.schema).parseSlice(element)

  tr.insert(selection.anchor, slice.content)
  selectionToInsertionEnd(tr, tr.steps.length - 1, -1)

  return true
}
