import type { TextareaRenderable } from "@opentui/core"
import { produce, type SetStoreFunction } from "solid-js/store"
import { useSDK } from "@tui/context/sdk"
import { useSync } from "@tui/context/sync"
import { useDialog } from "@tui/ui/dialog"
import * as Editor from "@tui/util/editor"
import { useRenderer } from "@opentui/solid"
import { DialogSkill } from "../dialog-skill"
import { DialogStash } from "../dialog-stash"
import { editorSelectionKey } from "@tui/context/editor"
import type { PromptInfo } from "./history"
import type { AutocompleteRef } from "./autocomplete"
import type { ExtmarkSyncDeps } from "./use-extmark-sync"
import type { PromptProps } from "."
import type { StoreShape } from "./use-prompt-store"

export type CommandDeps = {
  props: PromptProps
  getInput: () => TextareaRenderable
  store: StoreShape
  setStore: SetStoreFunction<StoreShape>
  autocomplete: () => AutocompleteRef | undefined
  extmarkSync: ExtmarkSyncDeps
  restoreExtmarks: (parts: PromptInfo["parts"]) => void
  submit: () => Promise<boolean>
  pasteAttachment: (file: { filename?: string; filepath?: string; content: string; mime: string }) => Promise<void>
  status: () => { type: string }
  editorContext: () => any
  stash: { list: () => any[]; push: (entry: any) => void; pop: () => any }
  command: any
  history: any
  lastSubmittedEditorSelectionKey: { value: string | undefined }
  setDismissedEditorSelectionKey: (v: string | undefined) => void
  promptPartTypeId: { value: number }
}

export function usePromptCommands(deps: CommandDeps) {
  const sdk = useSDK()
  const sync = useSync()
  const dialog = useDialog()
  const renderer = useRenderer()

  function dismissEditorContext() {
    deps.setDismissedEditorSelectionKey(editorSelectionKey(deps.editorContext()))
  }

  deps.command.register(() => {
    return [
      {
        title: "Clear prompt",
        value: "prompt.clear",
        category: "Prompt",
        hidden: true,
        onSelect: (d: any) => {
          const input = deps.getInput()
          input.extmarks.clear()
          input.clear()
          d.clear()
        },
      },
      {
        title: "Submit prompt",
        value: "prompt.submit",
        keybind: "input_submit",
        category: "Prompt",
        hidden: true,
        onSelect: async (d: any) => {
          const input = deps.getInput()
          if (!input.focused) return
          const handled = await deps.submit()
          if (!handled) return
          d.clear()
        },
      },
      {
        title: "Remove editor context",
        value: "prompt.editor_context.clear",
        category: "Prompt",
        enabled: Boolean(deps.editorContext()),
        onSelect: (d: any) => {
          dismissEditorContext()
          d.clear()
        },
      },
      {
        title: "Paste",
        value: "prompt.paste",
        keybind: "input_paste",
        category: "Prompt",
        hidden: true,
        onSelect: async () => {
          const Clipboard = await import("../../util/clipboard")
          const content = await Clipboard.read()
          if (content?.mime.startsWith("image/")) {
            await deps.pasteAttachment({ filename: "clipboard", mime: content.mime, content: content.data })
          }
        },
      },
      {
        title: "Interrupt session",
        value: "session.interrupt",
        keybind: "session_interrupt",
        category: "Session",
        hidden: true,
        enabled: deps.status().type !== "idle",
        onSelect: (d: any) => {
          const input = deps.getInput()
          if (deps.autocomplete()?.visible) return
          if (!input.focused) return
          if (deps.store.mode === "shell") {
            deps.setStore("mode", "normal")
            return
          }
          if (!deps.props.sessionID) return
          deps.setStore("interrupt", deps.store.interrupt + 1)
          setTimeout(() => { deps.setStore("interrupt", 0) }, 5000)
          if (deps.store.interrupt >= 2) {
            void sdk.client.session.abort({ sessionID: deps.props.sessionID })
            deps.setStore("interrupt", 0)
          }
          d.clear()
        },
      },
      {
        title: "Open editor",
        category: "Session",
        keybind: "editor_open",
        value: "prompt.editor",
        slash: { name: "editor" },
        onSelect: async (d: any) => {
          d.clear()
          const input = deps.getInput()
          const text = deps.store.prompt.parts
            .filter((p) => p.type === "text")
            .reduce((acc, p) => { if (!p.source) return acc; return acc.replace(p.source.text.value, p.text) }, deps.store.prompt.input)
          const nonTextParts = deps.store.prompt.parts.filter((p) => p.type !== "text")
          const content = await Editor.open({ value: text, renderer })
          if (!content) return
          input.setText(content)
          const updated = nonTextParts.map((part) => {
            let vt = ""
            if (part.type === "file" && part.source?.text) vt = part.source.text.value
            else if (part.type === "agent" && part.source) vt = part.source.value
            if (!vt) return part
            const idx = content.indexOf(vt)
            if (idx === -1) return null
            const end = idx + vt.length
            if (part.type === "file" && part.source?.text) return { ...part, source: { ...part.source, text: { ...part.source.text, start: idx, end } } }
            if (part.type === "agent" && part.source) return { ...part, source: { ...part.source, start: idx, end } }
            return part
          }).filter((p) => p !== null)
          deps.setStore("prompt", { input: content, parts: updated })
          deps.restoreExtmarks(updated)
          input.cursorOffset = Bun.stringWidth(content)
        },
      },
      {
        title: "Skills",
        value: "prompt.skills",
        category: "Prompt",
        slash: { name: "skills" },
        onSelect: () => {
          dialog.replace(() => (
            <DialogSkill
              onSelect={(skill: string) => {
                const input = deps.getInput()
                input.setText(`/${skill} `)
                deps.setStore("prompt", { input: `/${skill} `, parts: [] })
                input.gotoBufferEnd()
              }}
            />
          ))
        },
      },
    ]
  })

  deps.command.register(() => [
    {
      title: "Stash prompt",
      value: "prompt.stash",
      category: "Prompt",
      enabled: !!deps.store.prompt.input,
      onSelect: (d: any) => {
        if (!deps.store.prompt.input) return
        const input = deps.getInput()
        deps.stash.push({ input: deps.store.prompt.input, parts: deps.store.prompt.parts })
        input.extmarks.clear()
        input.clear()
        deps.setStore("prompt", { input: "", parts: [] })
        deps.setStore("extmarkToPartIndex", new Map())
        d.clear()
      },
    },
    {
      title: "Stash pop",
      value: "prompt.stash.pop",
      category: "Prompt",
      enabled: deps.stash.list().length > 0,
      onSelect: (d: any) => {
        const entry = deps.stash.pop()
        if (entry) {
          const input = deps.getInput()
          input.setText(entry.input)
          deps.setStore("prompt", { input: entry.input, parts: entry.parts })
          deps.restoreExtmarks(entry.parts)
          input.gotoBufferEnd()
        }
        d.clear()
      },
    },
    {
      title: "Stash list",
      value: "prompt.stash.list",
      category: "Prompt",
      enabled: deps.stash.list().length > 0,
      onSelect: () => {
        dialog.replace(() => (
          <DialogStash
            onSelect={(entry: any) => {
              const input = deps.getInput()
              input.setText(entry.input)
              deps.setStore("prompt", { input: entry.input, parts: entry.parts })
              deps.restoreExtmarks(entry.parts)
              input.gotoBufferEnd()
            }}
          />
        ))
      },
    },
  ])

  return { dismissEditorContext }
}
