import { createMemo, createSignal, onMount, onCleanup, Show, Switch, Match } from "solid-js"
import "opentui-spinner/solid"
import { useTheme } from "@tui/context/theme"
import { useKeybind } from "@tui/context/keybind"
import { useKV } from "../../context/kv"
import { useDialog } from "@tui/ui/dialog"
import { DialogAlert } from "../../ui/dialog-alert"
import { Locale } from "@/util/locale"
import { formatDuration } from "@/util/format"
import { t } from "@/util/i18n"
import { EmptyBorder } from "@tui/component/border"
import type { PromptInfo } from "./history"

export type PromptStatusBarProps = {
  sessionID?: string
  status: () => { type: string }
  store: {
    prompt: PromptInfo
    mode: "normal" | "shell"
    interrupt: number
    exitPress: number
  }
  hint: any
  usage: () => { context: string; cost?: string; health: string; remaining?: number; pct: number } | undefined
  borderHighlight: () => any
  spinnerDef: () => { frames: any; color: any }
  editorFileLabelDisplay: () => string | undefined
  onDismissEditorContext: () => void
}

export function PromptStatusBar(props: PromptStatusBarProps) {
  const { theme } = useTheme()
  const keybind = useKeybind()
  const kv = useKV()
  const dialog = useDialog()
  const [editorContextHover, setEditorContextHover] = createSignal(false)
  const [pointingHover, setPointingHover] = createSignal(false)
  const pointing = () => props.sessionID ? kv.get(`pointing:${props.sessionID}`) : undefined
  const pointingDisplay = createMemo(() => {
    const p = pointing()
    if (!p) return ""
    const segments = p.replace(/\\/g, "/").split("/").filter(Boolean)
    if (segments.length <= 3) return p
    return "..." + segments.slice(-2).join("/")
  })

  return (
    <>
      <box
        height={1}
        flexShrink={0}
        border={["left"]}
        borderColor={props.borderHighlight()}
        customBorderChars={{
          ...EmptyBorder,
          vertical: theme.backgroundElement.a !== 0 ? "╹" : " ",
        }}
      >
        <box
          height={1}
          border={["bottom"]}
          borderColor={theme.backgroundElement}
          customBorderChars={
            theme.backgroundElement.a !== 0
              ? { ...EmptyBorder, horizontal: "▀" }
              : { ...EmptyBorder, horizontal: " " }
          }
        />
      </box>
      <box width="100%" flexDirection="row" justifyContent="space-between">
        <Show when={props.status().type !== "idle"} fallback={props.hint ?? <text />}>
          <box
            flexDirection="row"
            gap={1}
            flexGrow={1}
            justifyContent={props.status().type === "retry" ? "space-between" : "flex-start"}
          >
            <box flexShrink={0} flexDirection="row" gap={1}>
              <box marginLeft={1}>
                <Show when={kv.get("animations_enabled", true)} fallback={<text fg={theme.textMuted}>[⋯]</text>}>
                  <spinner color={props.spinnerDef().color} frames={props.spinnerDef().frames} interval={40} />
                </Show>
              </box>
              <box flexDirection="row" gap={1} flexShrink={0}>
                <RetryInfo status={props.status} />
              </box>
            </box>
            <text fg={props.store.interrupt > 0 ? theme.primary : theme.text}>
              esc{" "}
              <span style={{ fg: props.store.interrupt > 0 ? theme.primary : theme.textMuted }}>
                {props.store.interrupt > 0 ? "again to interrupt" : "interrupt"}
              </span>
            </text>
          </box>
        </Show>
        <Show when={props.status().type !== "retry"}>
          <box gap={2} flexDirection="row">
            <Show when={props.store.exitPress > 0}>
              <text fg={theme.primary}>
                ctrl+c <span style={{ fg: theme.primary }}>again to exit</span>
              </text>
            </Show>
            <Show when={pointing()} keyed>
              {(dir) => (
                <text
                  fg={pointingHover() ? theme.primary : theme.secondary}
                  onMouseOver={() => setPointingHover(true)}
                  onMouseOut={() => setPointingHover(false)}
                  wrapMode="none"
                >
                  {pointingHover() ? `✕ ${dir}` : t("ui.statusbar.pointing", { path: pointingDisplay() })}
                </text>
              )}
            </Show>
            <Show when={props.editorFileLabelDisplay()}>
              {(file) => (
                <text
                  fg={theme.secondary}
                  onMouseOver={() => setEditorContextHover(true)}
                  onMouseOut={() => setEditorContextHover(false)}
                  onMouseUp={props.onDismissEditorContext}
                >
                  {editorContextHover() ? `x ${file()}` : file()}
                </text>
              )}
            </Show>
            <Switch>
              <Match when={props.store.mode === "normal"}>
                <Switch>
                  <Match when={props.usage()}>
                    {(item) => {
                      const u = item()
                      const color = u.health === "critical"
                        ? theme.error
                        : u.health === "warning"
                          ? theme.warning
                          : theme.textMuted
                      const parts = [u.context, u.cost].filter(Boolean)
                      return (
                        <text fg={color} wrapMode="none">
                          {parts.join(" · ")}
                        </text>
                      )
                    }}
                  </Match>
                  <Match when={true}>
                    <text fg={theme.text}>
                      {keybind.print("agent_cycle")}×2 <span style={{ fg: theme.textMuted }}>agents</span>
                    </text>
                  </Match>
                </Switch>
                <text fg={theme.text}>
                  {keybind.print("command_list")} <span style={{ fg: theme.textMuted }}>commands</span>
                </text>
              </Match>
              <Match when={props.store.mode === "shell"}>
                <text fg={theme.text}>
                  esc <span style={{ fg: theme.textMuted }}>exit shell mode</span>
                </text>
              </Match>
            </Switch>
          </box>
        </Show>
      </box>
    </>
  )
}

function RetryInfo(props: { status: () => { type: string } }) {
  const dialog = useDialog()
  const { theme } = useTheme()
  const retry = createMemo(() => {
    const s = props.status() as any
    if (s.type !== "retry") return
    return s
  })
  const message = createMemo(() => {
    const r = retry()
    if (!r) return
    if (r.message.includes("exceeded your current quota") && r.message.includes("gemini")) return "gemini is way too hot right now"
    if (r.message.length > 80) return r.message.slice(0, 80) + "..."
    return r.message
  })
  const isTruncated = createMemo(() => {
    const r = retry()
    if (!r) return false
    return r.message.length > 120
  })
  const [seconds, setSeconds] = createSignal(0)
  onMount(() => {
    const timer = setInterval(() => {
      const next = retry()?.next
      if (next) setSeconds(Math.round((next - Date.now()) / 1000))
    }, 1000)
    onCleanup(() => clearInterval(timer))
  })
  const handleClick = () => {
    const r = retry()
    if (!r) return
    if (isTruncated()) void DialogAlert.show(dialog, "Retry Error", r.message)
  }
  const retryText = () => {
    const r = retry()
    if (!r) return ""
    const base = message()
    const hint = isTruncated() ? " (click to expand)" : ""
    const duration = formatDuration(seconds())
    return base + hint + ` [retrying ${duration ? `in ${duration} ` : ""}attempt #${r.attempt}]`
  }
  return (
    <Show when={retry()}>
      <box onMouseUp={handleClick}>
        <text fg={theme.error}>{retryText()}</text>
      </box>
    </Show>
  )
}
