import { IconButton } from "@opencode-ai/ui/icon-button"
import { useI18n } from "@opencode-ai/ui/context/i18n"
import { SegmentedControlItemV2, SegmentedControlV2 } from "@opencode-ai/ui/v2/segmented-control-v2"
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2"
import { Icon } from "@opencode-ai/ui/v2/icon"
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
import type { SessionReviewDiffStyle } from "../../components/session-review"
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
import { makeEventListener } from "@solid-primitives/event-listener"
import { Show, createEffect, createMemo, createSignal, type JSX } from "solid-js"
import { getWorkerPool } from "../../pierre/worker"
import "./session-review-v2.css"

export const SESSION_REVIEW_V2_SIDEBAR_WIDTH_DEFAULT = 240
export const SESSION_REVIEW_V2_SIDEBAR_WIDTH_MIN = 200
export const SESSION_REVIEW_V2_SIDEBAR_WIDTH_MAX = 480

export type SessionReviewExpandMode = "expand" | "collapse"

export type SessionReviewV2Props = {
  title?: JSX.Element
  stats?: JSX.Element
  empty?: JSX.Element
  sidebarOpen?: boolean
  sidebar?: JSX.Element
  sidebarToggle?: JSX.Element
  activeFile?: string
  files: string[]
  onSelectFile: (file: string) => void
  diffStyle: SessionReviewDiffStyle
  onDiffStyleChange?: (style: SessionReviewDiffStyle) => void
  expandMode: SessionReviewExpandMode
  onExpandModeChange: (mode: SessionReviewExpandMode) => void
  preview?: JSX.Element
  hasDiffs: boolean
}

export type SessionReviewV2SidebarProps = {
  open: boolean
  title?: JSX.Element
  stats?: JSX.Element
  filter: string
  onFilterChange: (value: string) => void
  onFilterKeyDown?: JSX.EventHandlerUnion<HTMLInputElement, KeyboardEvent>
  width?: number
  onWidthChange?: (width: number) => void
  minWidth?: number
  maxWidth?: number
  viewportRef?: (element: HTMLDivElement) => void
  children?: JSX.Element
}

export function SessionReviewV2Sidebar(props: SessionReviewV2SidebarProps) {
  const i18n = useI18n()
  const [resizing, setResizing] = createSignal(false)
  const width = () => props.width ?? SESSION_REVIEW_V2_SIDEBAR_WIDTH_DEFAULT
  const minWidth = () => props.minWidth ?? SESSION_REVIEW_V2_SIDEBAR_WIDTH_MIN
  const maxWidth = () => props.maxWidth ?? SESSION_REVIEW_V2_SIDEBAR_WIDTH_MAX

  createEffect(() => {
    if (!resizing()) return
    const stop = () => setResizing(false)
    makeEventListener(document, "pointerup", stop)
    makeEventListener(document, "pointercancel", stop)
  })

  return (
    <div data-component="session-review-v2-sidebar-root">
      <aside
        data-slot="session-review-v2-sidebar"
        data-resizing={resizing() ? "" : undefined}
        aria-hidden={!props.open}
        inert={!props.open}
        style={{ width: props.open ? `${width()}px` : "0px" }}
      >
        <div data-slot="session-review-v2-sidebar-header">
          <div data-slot="session-review-v2-sidebar-title">{props.title}</div>
          {props.stats}
        </div>
        <div data-slot="session-review-v2-sidebar-filter">
          <TextInputV2
            type="search"
            value={props.filter}
            onInput={(event) => props.onFilterChange(event.currentTarget.value)}
            onKeyDown={props.onFilterKeyDown}
            showClearButton={props.filter.length > 0}
            clearLabel={i18n.t("ui.list.clearFilter")}
            onClearClick={() => props.onFilterChange("")}
            placeholder={i18n.t("ui.sessionReviewV2.filterFiles")}
            aria-label={i18n.t("ui.sessionReviewV2.filterFiles")}
            leadingIcon={
              <svg
                width="14"
                height="14"
                viewBox="0 0 14 14"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
                aria-hidden="true"
              >
                <path
                  d="M12.25 12.25L10.0625 10.0625M11.0833 6.41667C11.0833 8.994 8.994 11.0833 6.41667 11.0833C3.83934 11.0833 1.75 8.994 1.75 6.41667C1.75 3.83934 3.83934 1.75 6.41667 1.75C8.994 1.75 11.0833 3.83934 11.0833 6.41667Z"
                  stroke="currentColor"
                  stroke-linecap="square"
                />
              </svg>
            }
          />
        </div>
        <ScrollView
          data-slot="session-review-v2-sidebar-tree"
          class="group/file-tree-v2"
          thumbVisibility="scroll"
          viewportRef={props.viewportRef}
        >
          {props.children}
        </ScrollView>
      </aside>
      <Show when={props.open && props.onWidthChange}>
        <div data-slot="session-review-v2-sidebar-resize" onPointerDown={() => setResizing(true)}>
          <ResizeHandle
            direction="horizontal"
            size={width()}
            min={minWidth()}
            max={maxWidth()}
            onResize={(next) => props.onWidthChange?.(next)}
          />
        </div>
      </Show>
    </div>
  )
}

export function SessionReviewV2(props: SessionReviewV2Props) {
  const i18n = useI18n()

  createEffect(() => {
    getWorkerPool(props.diffStyle)
  })

  const fileIndex = () => {
    const files = props.files
    if (files.length === 0) return -1

    const active = props.activeFile
    const i = active ? files.indexOf(active) : -1
    if (i >= 0) return i
    return 0
  }

  const prev = () => {
    const files = props.files
    if (files.length === 0) return
    return files[(fileIndex() - 1 + files.length) % files.length]
  }

  const next = () => {
    const files = props.files
    if (files.length === 0) return
    return files[(fileIndex() + 1) % files.length]
  }

  const canCycle = () => props.files.length > 0
  const showCollapsedMeta = () => props.sidebarOpen === false
  // Memoize slot getters so Show conditions do not instantiate throwaway elements.
  const title = createMemo(() => props.title)
  const stats = createMemo(() => props.stats)

  const cycle = (file: string | undefined) => {
    if (!file) return
    props.onSelectFile(file)
  }

  // The prev/next tooltips advertise < and >; keep the keys working while the
  // pane is mounted, but never while typing in an input or comment editor.
  makeEventListener(document, "keydown", (event) => {
    if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.altKey) return
    if (event.key !== "<" && event.key !== ">") return
    const target = event.target
    if (target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select"))) return
    if (!props.hasDiffs || !canCycle()) return
    event.preventDefault()
    cycle(event.key === "<" ? prev() : next())
  })

  return (
    <div data-component="session-review-v2">
      <div data-slot="session-review-v2-body">
        {props.sidebar}

        <div data-slot="session-review-v2-preview">
          <Show when={props.hasDiffs} fallback={props.empty}>
            <div data-slot="session-review-v2-toolbar">
              <div data-slot="session-review-v2-toolbar-group" class="session-review-v2-toolbar-group--start">
                {props.sidebarToggle}
                <Show when={showCollapsedMeta()}>
                  <div data-slot="session-review-v2-toolbar-collapsed-meta">
                    <Show when={title()}>
                      <div data-slot="session-review-v2-toolbar-title">{title()}</div>
                    </Show>
                    {stats()}
                    <Show when={canCycle()}>
                      <span data-slot="session-review-v2-file-position">
                        {fileIndex() + 1}/{props.files.length}
                      </span>
                    </Show>
                  </div>
                </Show>
                <div data-slot="session-review-v2-toolbar-group">
                  <TooltipV2
                    openDelay={2000}
                    value={
                      <>
                        {i18n.t("ui.sessionReviewV2.previousFile")}
                        <KeybindV2 keys={["<"]} variant="neutral" />
                      </>
                    }
                  >
                    <IconButton
                      icon="arrow-left"
                      variant="ghost"
                      size="small"
                      class="session-review-v2-file-nav-button"
                      disabled={!canCycle()}
                      onClick={() => {
                        const file = prev()
                        if (!file) return
                        props.onSelectFile(file)
                      }}
                      aria-label={i18n.t("ui.sessionReviewV2.previousFile")}
                    />
                  </TooltipV2>
                  <TooltipV2
                    openDelay={2000}
                    value={
                      <>
                        {i18n.t("ui.sessionReviewV2.nextFile")}
                        <KeybindV2 keys={[">"]} variant="neutral" />
                      </>
                    }
                  >
                    <IconButton
                      icon="arrow-right"
                      variant="ghost"
                      size="small"
                      class="session-review-v2-file-nav-button"
                      disabled={!canCycle()}
                      onClick={() => {
                        const file = next()
                        if (!file) return
                        props.onSelectFile(file)
                      }}
                      aria-label={i18n.t("ui.sessionReviewV2.nextFile")}
                    />
                  </TooltipV2>
                </div>
              </div>
              <div data-slot="session-review-v2-toolbar-group" class="session-review-v2-toolbar-group--segments">
                <SegmentedControlV2
                  value={props.expandMode}
                  onChange={(value) => {
                    if (value !== "expand" && value !== "collapse") return
                    props.onExpandModeChange(value)
                  }}
                  class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
                  aria-label={i18n.t("ui.sessionReviewV2.expandMode")}
                >
                  <TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.showAllLines")}>
                    <SegmentedControlItemV2 value="expand" aria-label={i18n.t("ui.sessionReviewV2.showAllLines")}>
                      <Icon name="expand" />
                    </SegmentedControlItemV2>
                  </TooltipV2>
                  <TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
                    <SegmentedControlItemV2 value="collapse" aria-label={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
                      <Icon name="collapse" />
                    </SegmentedControlItemV2>
                  </TooltipV2>
                </SegmentedControlV2>
                <Show when={props.onDiffStyleChange}>
                  <SegmentedControlV2
                    value={props.diffStyle}
                    onChange={(value) => {
                      if (value !== "unified" && value !== "split") return
                      props.onDiffStyleChange?.(value)
                    }}
                    class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
                    aria-label={i18n.t("ui.sessionReviewV2.diffView")}
                  >
                    <TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
                      <SegmentedControlItemV2 value="unified" aria-label={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
                        <Icon name="unified" />
                      </SegmentedControlItemV2>
                    </TooltipV2>
                    <TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.splitDiff")}>
                      <SegmentedControlItemV2 value="split" aria-label={i18n.t("ui.sessionReviewV2.splitDiff")}>
                        <Icon name="split" />
                      </SegmentedControlItemV2>
                    </TooltipV2>
                  </SegmentedControlV2>
                </Show>
              </div>
            </div>
            <Show when={props.activeFile} fallback={<div data-slot="session-review-v2-empty">{props.empty}</div>}>
              {props.preview}
            </Show>
          </Show>
        </div>
      </div>
    </div>
  )
}

export function SessionReviewV2SidebarToggle(props: { opened: boolean; onToggle: () => void }) {
  const i18n = useI18n()

  return (
    <TooltipV2 value={i18n.t("ui.sessionReviewV2.toggleSidebar")}>
      <IconButtonV2
        variant="ghost"
        size="small"
        class="session-review-v2-sidebar-toggle"
        aria-label={i18n.t("ui.sessionReviewV2.toggleSidebar")}
        aria-expanded={props.opened}
        onClick={props.onToggle}
        icon={<Icon name="filetree" />}
      />
    </TooltipV2>
  )
}
