import { TextAttributes } from "@opentui/core"
import { useKeyboard, useTerminalDimensions } from "@opentui/solid"
import type { VcsFileStatus } from "@opencode-ai/client"
import { createMemo, For } from "solid-js"
import { createStore } from "solid-js/store"
import { FilePath } from "../ui/file-path"
import { useTheme } from "../context/theme"
import { useConfig } from "../config"
import { useDialog, type DialogContext } from "../ui/dialog"
import { getScrollAcceleration } from "../util/scroll"

const options = ["no", "yes"] as const

export type WorkspaceFileChangesChoice = (typeof options)[number]

function statusLabel(status: VcsFileStatus["status"]) {
  if (status === "added") return "A"
  if (status === "deleted") return "D"
  return "M"
}

function changeCountWidth(file: VcsFileStatus) {
  // The "plus 2" is for spaces
  return `${file.additions ? `+${file.additions}` : ""}${file.deletions ? ` -${file.deletions}` : ""}`.length + 2
}

export function DialogWorkspaceFileChanges(props: {
  files: VcsFileStatus[]
  onSelect: (choice: WorkspaceFileChangesChoice) => void
  title?: string
  message?: string
}) {
  const dialog = useDialog()
  const { themeV2 } = useTheme().contextual("elevated")
  const { themeV2: overlayTheme } = useTheme().contextual("overlay")
  const config = useConfig().data
  const dimensions = useTerminalDimensions()
  const scrollAcceleration = createMemo(() => getScrollAcceleration(config))
  const [store, setStore] = createStore({ active: "yes" as WorkspaceFileChangesChoice })
  const height = createMemo(() => Math.min(props.files.length, 8))
  const fileNameWidth = createMemo(() =>
    Math.max(2, Math.min(60, dimensions().width - 2) - 6 - Math.max(7, ...props.files.map(changeCountWidth))),
  )

  function confirm() {
    props.onSelect(store.active)
    dialog.clear()
  }

  useKeyboard((evt) => {
    if (evt.name === "return") {
      evt.preventDefault()
      evt.stopPropagation()
      confirm()
      return
    }
    if (evt.name === "left") {
      evt.preventDefault()
      evt.stopPropagation()
      const index = options.indexOf(store.active)
      setStore("active", options[Math.max(index - 1, 0)])
      return
    }
    if (evt.name === "right") {
      evt.preventDefault()
      evt.stopPropagation()
      const index = options.indexOf(store.active)
      setStore("active", options[Math.min(index + 1, options.length - 1)])
    }
  })

  return (
    <box gap={1}>
      <box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
        <text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
          {props.title ?? "File Changes Found"}
        </text>
        <text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
          esc
        </text>
      </box>
      <box paddingLeft={2} paddingRight={2}>
        <text fg={themeV2.text.subdued()} wrapMode="word">
          {props.message ?? "Do you want to move these changes with the session?"}
        </text>
      </box>
      <scrollbox
        height={height()}
        backgroundColor={overlayTheme.background()}
        scrollbarOptions={{ visible: false }}
        scrollAcceleration={scrollAcceleration()}
      >
        <For each={props.files}>
          {(item) => (
            <box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
              <box flexDirection="row" minWidth={0} flexShrink={1}>
                <box width={2} flexShrink={0}>
                  <text fg={overlayTheme.text.subdued()}>{statusLabel(item.status)}</text>
                </box>
                <FilePath value={item.file} maxWidth={fileNameWidth()} fg={overlayTheme.text.subdued()} />
              </box>
              <box flexDirection="row" gap={1} minWidth={7} flexShrink={0} justifyContent="flex-end">
                <text>
                  {" "}
                  {item.additions ? (
                    <span style={{ fg: overlayTheme.diff.text.added() }}>+{item.additions}</span>
                  ) : null}
                  {item.deletions ? (
                    <span style={{ fg: overlayTheme.diff.text.removed() }}> -{item.deletions}</span>
                  ) : null}
                </text>
              </box>
            </box>
          )}
        </For>
      </scrollbox>
      <box flexDirection="row" justifyContent="flex-end" paddingLeft={2} paddingRight={2} paddingBottom={1}>
        <For each={options}>
          {(item) => (
            <box
              paddingLeft={2}
              paddingRight={2}
              backgroundColor={item === store.active ? themeV2.background.action("focused") : undefined}
              onMouseUp={() => {
                setStore("active", item)
                props.onSelect(item)
                dialog.clear()
              }}
            >
              <text fg={item === store.active ? themeV2.text.action("focused") : themeV2.text.subdued()}>{item}</text>
            </box>
          )}
        </For>
      </box>
    </box>
  )
}

DialogWorkspaceFileChanges.show = (
  dialog: DialogContext,
  files: VcsFileStatus[],
  options?: { title?: string; message?: string },
) => {
  return new Promise<WorkspaceFileChangesChoice | undefined>((resolve) => {
    dialog.replace(
      () => <DialogWorkspaceFileChanges files={files} onSelect={resolve} {...options} />,
      () => resolve(undefined),
    )
  })
}
