import {
  createTextEditSession,
  resizeTextNodeForEdit,
  snapshotTextNode,
  textSnapshotChanged,
  type TextEditSession
} from './text/session'
import type { EditorContext } from './types'

export function createTextActions(ctx: EditorContext) {
  let activeSession: TextEditSession | null = null

  function startTextEditing(nodeId: string) {
    const te = ctx.getTextEditor()
    if (ctx.state.editingTextId) commitTextEdit()
    const node = ctx.graph.getNode(nodeId)
    if (!node) return
    activeSession = createTextEditSession(node)
    ctx.state.editingTextId = nodeId
    if (te) {
      te.setRenderer(ctx.getRenderer())
      te.start(node)
    }
    ctx.requestRender()
  }

  function commitTextEdit() {
    const te = ctx.getTextEditor()
    if (!te?.isActive) {
      ctx.state.editingTextId = null
      activeSession = null
      return
    }
    const paragraph = te.state?.paragraph ?? null
    const result = te.stop()
    if (!result) {
      ctx.state.editingTextId = null
      activeSession = null
      ctx.requestRender()
      return
    }
    const before = activeSession?.before ?? { text: '', styleRuns: [], size: {} }
    const node = ctx.graph.getNode(result.nodeId)
    const after = snapshotTextNode(node, result.text)
    after.text = result.text
    const sizeChanges = before.text !== after.text ? resizeTextNodeForEdit(node, paragraph) : {}
    if (Object.keys(sizeChanges).length > 0) after.size = sizeChanges
    ctx.graph.updateNode(result.nodeId, {
      text: after.text,
      styleRuns: after.styleRuns,
      ...sizeChanges
    })
    ctx.state.editingTextId = null
    activeSession = null

    if (textSnapshotChanged(before, after)) {
      ctx.undo.push({
        label: 'Edit text',
        forward: () => {
          ctx.graph.updateNode(result.nodeId, {
            text: after.text,
            styleRuns: after.styleRuns,
            ...after.size
          })
        },
        inverse: () => {
          ctx.graph.updateNode(result.nodeId, {
            text: before.text,
            styleRuns: before.styleRuns,
            ...before.size
          })
        }
      })
    }
  }

  return { startTextEditing, commitTextEdit }
}
