import type { TextareaRenderable } from "@opentui/core"
import { onMount, onCleanup } from "solid-js"
import { useEditorContext } from "@tui/context/editor"
import { normalizeMentionPath, createFilePart } from "./autocomplete-utils"
import type { AutocompleteRef, AutocompleteStore } from "./autocomplete-types"

type RefDeps = {
  store: AutocompleteStore
  setStore: (key: string, value: unknown) => void
  input: () => TextareaRenderable
  options: () => import("./autocomplete-types").AutocompleteOption[]
  show: (mode: "@" | "/") => void
  hide: () => void
  select: () => void
  expandDirectory: () => void
  move: (dir: -1 | 1) => void
  insertPart: (text: string, part: any) => void
  syncDir: string
  setRef: (ref: AutocompleteRef) => void
}

export function useAutocompleteRef(deps: RefDeps) {
  const editor = useEditorContext()

  onMount(() => {
    const unsubscribeMention = editor.onMention((mention) => {
      const item = normalizeMentionPath(mention.filePath, deps.syncDir || process.cwd())
      const lineRange = {
        startLine: mention.lineStart,
        endLine: mention.lineEnd > mention.lineStart ? mention.lineEnd : undefined,
      }
      const { filename, part } = createFilePart(item, deps.syncDir, lineRange)
      const index = deps.store.visible === "@" ? deps.store.index : deps.input().cursorOffset
      deps.setStore("visible", false)
      deps.setStore("index", index)
      deps.insertPart(filename, part)
    })
    onCleanup(() => unsubscribeMention())

    deps.setRef({
      get visible() {
        return deps.store.visible
      },
      dismiss() {
        if (!deps.store.visible) return
        deps.setStore("visible", false)
      },
      onInput(value) {
        if (deps.store.visible) {
          const inp = deps.input()
          if (
            inp.cursorOffset <= deps.store.index ||
            inp.getTextRange(deps.store.index, inp.cursorOffset).match(/\s/) ||
            (deps.store.visible === "/" && value.match(/^\S+\s+\S+\s*$/))
          ) {
            deps.hide()
          }
          return
        }
        const offset = deps.input().cursorOffset
        if (offset === 0) return
        if (value.startsWith("/") && !value.slice(0, offset).match(/\s/)) {
          deps.show("/")
          deps.setStore("index", 0)
          return
        }
        const text = value.slice(0, offset)
        const idx = text.lastIndexOf("@")
        if (idx === -1) return
        const between = text.slice(idx)
        const before = idx === 0 ? undefined : value[idx - 1]
        if ((before === undefined || /\s/.test(before)) && !between.match(/\s/)) {
          deps.show("@")
          deps.setStore("index", idx)
        }
      },
      onKeyDown(e) {
        if (deps.store.visible) {
          const name = e.name?.toLowerCase()
          const ctrlOnly = e.ctrl && !e.meta && !e.shift
          if (name === "up" || (ctrlOnly && name === "p")) {
            deps.setStore("input", "keyboard")
            deps.move(-1)
            e.preventDefault()
            return
          }
          if (name === "down" || (ctrlOnly && name === "n")) {
            deps.setStore("input", "keyboard")
            deps.move(1)
            e.preventDefault()
            return
          }
          if (name === "escape") { deps.hide(); e.preventDefault(); return }
          if (name === "return") { deps.select(); e.preventDefault(); return }
          if (name === "tab") {
            const selected = deps.options()[deps.store.selected]
            selected?.isDirectory ? deps.expandDirectory() : deps.select()
            e.preventDefault()
            return
          }
          if (name === "right" && deps.input().cursorOffset <= deps.store.index) {
            deps.hide()
            return
          }
        }
        if (!deps.store.visible) {
          if (e.name === "@") {
            const off = deps.input().cursorOffset
            const before = off === 0 ? undefined : deps.input().getTextRange(off - 1, off)
            if (before === undefined || before === "" || /\s/.test(before)) deps.show("@")
          }
          if (e.name === "/" && deps.input().cursorOffset === 0) deps.show("/")
        }
      },
      onCursorChange() {
        if (!deps.store.visible) return
        const cursor = deps.input().cursorOffset
        const value = deps.input().plainText
        if (
          cursor <= deps.store.index ||
          deps.input().getTextRange(deps.store.index, cursor).match(/\s/) ||
          (deps.store.visible === "/" && value.match(/^\S+\s+\S+\s*$/))
        ) {
          deps.hide()
        }
      },
    })
  })
}
