import type { NodeType, Schema } from 'prosemirror-model'
import {
  inputRules,
  wrappingInputRule,
  smartQuotes,
  emDash,
  ellipsis,
  InputRule,
} from 'prosemirror-inputrules'

const blockQuoteRule = (nodeType: NodeType) => wrappingInputRule(/^\s*>\s$/, nodeType)

const orderedListRule = (nodeType: NodeType) => (
  wrappingInputRule(
    /^(\d+)\.\s$/, 
    nodeType, 
    match => ({order: +match[1]}),
    (match, node) => node.childCount + node.attrs.order === +match[1],
  )
)

const bulletListRule = (nodeType: NodeType) => wrappingInputRule(/^\s*([-+*])\s$/, nodeType)

const codeRule = () => {
  const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/
  
  return new InputRule(inputRegex, (state, match, start, end) => {
    const { schema } = state

    const tr = state.tr.insertText(`${match[2]} `, start, end)
    const mark = schema.marks.code.create()

    return tr.addMark(start, start + match[2].length, mark)
  })
}

const linkRule = () => {
  const urlRegEx = /(?:https?:\/\/)?[\w-]+(?:\.[\w-]+)+\.?(?:\d+)?(?:\/\S*)?$/
  
  return new InputRule(urlRegEx, (state, match, start, end) => {
    const { schema } = state

    const tr = state.tr.insertText(match[0], start, end)
    const mark = schema.marks.link.create({ href: match[0], title: match[0] })

    return tr.addMark(start, start + match[0].length, mark)
  })
}

export const buildInputRules = (schema: Schema) => {
  const rules = [
    ...smartQuotes,
    ellipsis,
    emDash,
  ]
  rules.push(blockQuoteRule(schema.nodes.blockquote))
  rules.push(orderedListRule(schema.nodes.ordered_list))
  rules.push(bulletListRule(schema.nodes.bullet_list))
  rules.push(codeRule())
  rules.push(linkRule())

  return inputRules({ rules })
}