import type { KeyEvent, TextareaRenderable } from "@opentui/core"
import type { SetStoreFunction } from "solid-js/store"
import type { ClawAutocompleteRef, ClawSlashOption } from "./autocomplete-types"

type StoreState = { index: number; selected: number; visible: boolean }

type RefDeps = {
  store: StoreState
  setStore: SetStoreFunction<StoreState>
  options: () => ClawSlashOption[]
  input: () => TextareaRenderable | undefined
  value: () => string
  show: () => void
  hide: () => void
  select: () => void
  move: (dir: -1 | 1) => void
  dismiss: () => void
  keybinds: (enabled: boolean) => void
}

export function createAutocompleteRef(deps: RefDeps): ClawAutocompleteRef {
  const { store, setStore, options, input, value, show, hide, select, move, dismiss, keybinds } = deps

  return {
    get visible() {
      return store.visible
    },
    dismiss() {
      dismiss()
    },
    onInput(val: string) {
      const inp = input()
      if (!inp) return
      if (store.visible) {
        if (
          inp.cursorOffset <= store.index ||
          inp.getTextRange(store.index, inp.cursorOffset).match(/\s/) ||
          val.match(/^\S+\s+\S+\s*$/)
        ) {
          hide()
        }
        return
      }
      const offset = inp.cursorOffset
      if (offset === 0) return
      if (val.startsWith("/") && !val.slice(0, offset).match(/\s/)) {
        show()
        setStore("index", 0)
      }
    },
    onCursorChange() {
      if (!store.visible) return
      const inp = input()
      if (!inp) return
      const cursor = inp.cursorOffset
      const text = inp.plainText
      if (
        cursor <= store.index ||
        inp.getTextRange(store.index, cursor).match(/\s/) ||
        text.match(/^\S+\s+\S+\s*$/)
      ) {
        hide()
      }
    },
    onKeyDown(e: KeyEvent) {
      if (store.visible) {
        const name = e.name?.toLowerCase()
        const ctrlOnly = e.ctrl && !e.meta && !e.shift
        const isNavUp = name === "up" || (ctrlOnly && name === "p")
        const isNavDown = name === "down" || (ctrlOnly && name === "n")
        if (isNavUp) {
          move(-1)
          e.preventDefault()
          return
        }
        if (isNavDown) {
          move(1)
          e.preventDefault()
          return
        }
        if (name === "escape") {
          hide()
          e.preventDefault()
          return
        }
        if (name === "return" || name === "tab") {
          select()
          e.preventDefault()
          return
        }
        if (name === "right") {
          const inp = input()
          if (inp && inp.cursorOffset <= store.index) {
            hide()
            return
          }
        }
        return
      }
      if (e.name === "/") {
        const inp = input()
        if (inp && inp.cursorOffset === 0) show()
      }
    },
  }
}
