import { BoxRenderable, TextareaRenderable, RGBA } from "@opentui/core"
import { createEffect, createMemo, createSignal } from "solid-js"
import { useTheme, tint } from "@tui/context/theme"
import { SplitBorder } from "@tui/component/border"
import { useCommandDialog } from "../dialog-command"
import { type AutocompleteRef, Autocomplete } from "./autocomplete"
import { usePromptHistory, type PromptInfo } from "./history"
import { usePromptStash } from "./stash"
import { usePromptStore } from "./use-prompt-store"
import { usePromptMemos } from "./use-prompt-memos"
import { usePromptSubmit } from "./use-prompt-submit"
import { usePromptCommands } from "./use-prompt-commands"
import { restoreExtmarksFromParts, syncExtmarksWithPromptParts, type ExtmarkSyncDeps } from "./use-extmark-sync"
import { PromptMeta } from "./PromptMeta"
import { PromptStatusBar } from "./PromptStatusBar"
import { PromptTextarea } from "./prompt-textarea"
import { useLocal } from "@tui/context/local"

export type PromptProps = {
  sessionID?: string
  workspaceID?: string
  visible?: boolean
  disabled?: boolean
  onSubmit?: () => void
  ref?: (ref: PromptRef | undefined) => void
  hint?: import("@opentui/solid").JSX.Element
  right?: import("@opentui/solid").JSX.Element
  showPlaceholder?: boolean
  placeholders?: { normal?: string[]; shell?: string[] }
}

export type PromptRef = {
  focused: boolean
  current: PromptInfo
  set(prompt: PromptInfo): void
  reset(): void
  blur(): void
  focus(): void
  submit(): void
}

function fadeColor(color: RGBA, alpha: number) {
  return RGBA.fromValues(color.r, color.g, color.b, color.a * alpha)
}

export function Prompt(props: PromptProps) {
  let input!: TextareaRenderable
  let anchor!: BoxRenderable
  let autocomplete!: AutocompleteRef
  let promptPartTypeId = 0

  const local = useLocal()
  const { theme, syntax } = useTheme()
  const command = useCommandDialog()
  const history = usePromptHistory()
  const stash = usePromptStash()
  const [auto, setAuto] = createSignal<AutocompleteRef>()

  const fileStyleId = syntax().getStyleId("extmark.file")!
  const agentStyleId = syntax().getStyleId("extmark.agent")!
  const pasteStyleId = syntax().getStyleId("extmark.paste")!

  function getInput() { return input }

  const extmarkSync: ExtmarkSyncDeps = {
    getInput,
    get setStore() { return _setStore },
    fileStyleId,
    agentStyleId,
    pasteStyleId,
    get promptPartTypeId() { return promptPartTypeId },
  }

  function restoreExtmarks(parts: PromptInfo["parts"]) {
    restoreExtmarksFromParts(extmarkSync, parts)
  }

  function syncExtmarks() {
    syncExtmarksWithPromptParts(extmarkSync)
  }

  const list = createMemo(() => props.placeholders?.normal ?? [])

  const { store, setStore: _setStore, ref, setAuto: _setAuto } = usePromptStore({
    props,
    getInput,
    extmarkSync,
    restoreExtmarks,
    list,
  })

  const memos = usePromptMemos({ props, store })

  const lastSubmittedEditorSelectionKey = { value: undefined as string | undefined }

  const { submit, pasteText, pasteAttachment } = usePromptSubmit({
    props,
    getInput,
    store,
    setStore: _setStore,
    autocomplete: () => autocomplete,
    extmarkSync,
    syncExtmarks,
    history,
    lastSubmittedEditorSelectionKey,
    editorContext: memos.editorContext,
    exit: async () => { const { useExit } = await import("../../context/exit"); await useExit()() },
  })

  _setAuto((r: any) => { autocomplete = r; setAuto(() => r as any); return r })

  const { dismissEditorContext } = usePromptCommands({
    props,
    getInput,
    store,
    setStore: _setStore,
    autocomplete: () => autocomplete,
    extmarkSync,
    restoreExtmarks,
    submit,
    pasteAttachment,
    status: memos.status,
    editorContext: memos.editorContext,
    stash,
    command,
    history,
    lastSubmittedEditorSelectionKey,
    setDismissedEditorSelectionKey: memos.setDismissedEditorSelectionKey,
    promptPartTypeId: { get value() { return promptPartTypeId } },
  })

  createEffect(() => {
    if (!input) return
    if (props.disabled) input.cursorColor = theme.backgroundElement
    if (!props.disabled) input.cursorColor = theme.text
  })

  const showVariant = createMemo(() => {
    const variants = local.model.variant.list()
    if (variants.length === 0) return false
    return !!local.model.variant.current()
  })

  return (
    <>
      <Autocomplete
        sessionID={props.sessionID}
        ref={(r) => { autocomplete = r; setAuto(() => r) }}
        anchor={() => anchor}
        input={() => input}
        setPrompt={(cb) => _setStore("prompt", cb as any)}
        setExtmark={(partIndex, extmarkId) => {
          _setStore("extmarkToPartIndex", (map: Map<number, number>) => {
            const newMap = new Map(map); newMap.set(extmarkId, partIndex); return newMap
          })
        }}
        value={store.prompt.input}
        fileStyleId={fileStyleId}
        agentStyleId={agentStyleId}
        promptPartTypeId={() => promptPartTypeId}
      />
      <box ref={(r) => (anchor = r)} visible={props.visible !== false}>
        <box border={["left"]} borderColor={memos.borderHighlight()} customBorderChars={{ ...SplitBorder.customBorderChars, bottomLeft: "╹" }}>
          <box paddingLeft={2} paddingRight={2} paddingTop={1} flexShrink={0} backgroundColor={theme.backgroundElement} flexGrow={1}>
            <PromptTextarea
              props={props}
              getStore={() => store}
              setStore={(k: string, ...a: any[]) => (_setStore as any)(k, ...a)}
              setStoreFull={(k: any, v: any) => (_setStore as any)(k, v)}
              getInput={getInput}
              autocomplete={autocomplete as any}
              submit={submit}
              pasteText={pasteText}
              pasteAttachment={pasteAttachment}
              restoreExtmarks={restoreExtmarks}
              syncExtmarks={syncExtmarks}
              history={history as any}
              placeholderText={memos.placeholderText}
              promptPartTypeId={promptPartTypeId}
              ref={ref}
            />
            <PromptMeta
              mode={store.mode}
              agentName={local.agent.current()?.name}
              agentDisplayName={local.agent.current()?.displayName}
              highlight={memos.highlight()}
              agentAlpha={memos.agentMetaAlpha()}
              modelAlpha={memos.modelMetaAlpha()}
              variantAlpha={memos.variantMetaAlpha()}
              textMuted={theme.textMuted}
              textColor={theme.text}
              providerLabel={memos.currentProviderLabel()}
              modelName={local.model.parsed().model}
              showVariant={showVariant()}
              variantName={local.model.variant.current()}
              warningColor={theme.warning}
              hasRightContent={!!props.right}
              right={props.right}
            />
          </box>
        </box>
        <PromptStatusBar
          sessionID={props.sessionID}
          status={memos.status}
          store={store}
          hint={props.hint}
          usage={memos.usage}
          borderHighlight={memos.borderHighlight}
          spinnerDef={memos.spinnerDef}
          editorFileLabelDisplay={memos.editorFileLabelDisplay}
          onDismissEditorContext={dismissEditorContext}
        />
      </box>
    </>
  )
}
