import type { VNode } from 'vue'
import type { UiThemeContext } from '../../theme'
import {
  createTextRestrictionPlugin,
  TBox,
  TDialog,
  textCellWidth,
  TInput,
  TSelect,
  TText,
} from '@simon_he/vue-tui'
import { h } from 'vue'
import { withFocusedInputTip } from '../input-clear-tip'
import {
  computeConfigDialogLayout,
  getConfigDialogStrings,
  nextInterleavedThinkingValue,
} from './view-model'

export type ConfigDialogFocusedField =
  | 'contextWindow'
  | 'maxTokens'
  | 'temperature'
  | 'shortcutCommands'
  | 'shortcutTimeline'
  | 'shortcutNewSession'

export type ConfigDialogProps = Readonly<{
  modelValue: boolean
  w: number
  h: number
  backdrop?: boolean
  showToast?: (text: string) => void
  contextWindow: string
  contextWindowLocked?: boolean
  maxTokens: string
  temperature: string
  interleavedThinking: boolean
  interleavedThinkingLocked?: boolean
  shortcutCommands: string
  shortcutTimeline: string
  shortcutNewSession: string
  focusedField?: ConfigDialogFocusedField | null
}>

export type ConfigDialogEmits = Readonly<{
  updateModelValue: (v: boolean) => void
  updateContextWindow: (v: string) => void
  updateMaxTokens: (v: string) => void
  updateTemperature: (v: string) => void
  updateInterleavedThinking: (v: boolean) => void
  updateShortcutCommands: (v: string) => void
  updateShortcutTimeline: (v: string) => void
  updateShortcutNewSession: (v: string) => void
  setFocusedField?: (v: ConfigDialogFocusedField | null) => void
  apply: () => void
  cancel: () => void
}>

type KeydownEventLike = Readonly<{
  key?: string
  shiftKey?: boolean
  ctrlKey?: boolean
  metaKey?: boolean
  altKey?: boolean
  preventDefault?: () => void
  stopPropagation?: () => void
}>

type ConfirmButtonLike = Readonly<{ value?: string }>

const numericPlugin = createTextRestrictionPlugin({
  name: 'numericOnly',
  rules: [{ allowChars: /[0-9.]/ }],
})

const temperaturePlugin = createTextRestrictionPlugin({
  name: 'temperatureNumeric',
  rules: [{ allowChars: /[0-9.]/ }, { allow: /^\d*(?:\.\d*)?$/ }],
})

/**
 * Render the CLI Settings dialog.
 *
 * Note: this function performs rendering side effects (VNode creation). Pure layout
 * decisions are delegated to `computeConfigDialogLayout`.
 */
export function renderConfigDialog(
  props: ConfigDialogProps,
  emit: ConfigDialogEmits,
  ui: UiThemeContext,
): VNode | null {
  if (!props.modelValue) return null

  const layout = computeConfigDialogLayout({
    w: props.w,
    h: props.h,
  })
  const strings = getConfigDialogStrings()

  const dialogBg = ui.token('dialog.chrome')?.bg
  const dialogBgStyle = dialogBg ? { bg: dialogBg } : undefined
  const chromeStyle = ui.style(['dialog.chrome'])
  const bodyStyle = chromeStyle
  const hintStyle = ui.style(['dialog.chrome', 'text.muted'])
  const boxStyle = ui.style(['dialog.chrome', 'dialog.chrome'])
  const fieldStyle = ui.style(['input.field'], dialogBgStyle)
  // Highlight rows should use the theme's select token; do not override bg with the dialog chrome bg.
  const selectHighlightStyle = ui.style(['select.item'])

  const commonInputProps = {
    cursorToEndOnFirstFocus: true,
    cursorToEndOnExternalUpdate: true,
    style: fieldStyle,
    zIndex: 1002,
  } as const
  const focusedField = props.focusedField ?? null
  const isShortcutFocused =
    focusedField === 'shortcutCommands' ||
    focusedField === 'shortcutTimeline' ||
    focusedField === 'shortcutNewSession'

  const topHintNode = layout.showHint
    ? h(TText, {
        x: 0,
        y: 0,
        w: layout.innerW,
        value: strings.hint,
        style: hintStyle,
      })
    : null

  const shortcutLabels = [
    strings.shortcutCommandsLabel,
    strings.shortcutTimelineLabel,
    strings.shortcutNewSessionLabel,
  ]
  const maxShortcutLabelW = Math.max(
    0,
    ...shortcutLabels.map((l) => textCellWidth(l)),
  )
  const shortcutLabelW = Math.max(
    0,
    Math.min(layout.innerW - 4, maxShortcutLabelW) + 1,
  )
  const shortcutInputX = Math.max(
    0,
    Math.min(layout.innerW - 2, shortcutLabelW + 1),
  )
  const shortcutInputW = Math.max(0, layout.innerW - 2 - shortcutInputX)

  return h(
    TDialog as any,
    {
      modelValue: props.modelValue,
      'onUpdate:modelValue': (v: boolean) => emit.updateModelValue(v),
      onKeydownCapture: (e: KeydownEventLike) => {
        if (e?.key === 'Escape') {
          e.preventDefault?.()
          e.stopPropagation?.()
          emit.cancel()
          emit.updateModelValue(false)
        }
      },
      w: layout.dialogW,
      h: layout.dialogH,
      title: strings.title,
      placement: 'center',
      tabMode: 'wrapFromButtons',
      // ChatPage often has dynamic content underneath (streaming, status, input panel).
      // Using a backdrop there reduces visual artifacts from overlapping content.
      backdrop: Boolean(props.backdrop),
      closeOnBackdrop: false,
      padding: 1,
      style: chromeStyle,
      buttons: [
        {
          label: strings.apply,
          value: 'apply',
          kind: 'primary',
          default: true,
        },
        { label: strings.cancel, value: 'cancel' },
      ],
      onConfirm: (btn: ConfirmButtonLike | null | undefined) => {
        if (btn?.value === 'apply') emit.apply()
        else emit.cancel()
      },
      onClose: () => emit.cancel(),
      closeOnConfirm: false,
    },
    () => [
      h(TText, {
        x: 0,
        y: 0,
        w: layout.innerW,
        h: layout.contentH,
        value: '',
        style: bodyStyle,
      }),
      topHintNode,

      // Row 1: Context Window (full width)
      h(
        TBox,
        {
          x: 0,
          y: layout.samplingY,
          w: layout.contextWindowW,
          h: layout.fieldBoxH,
          border: true,
          title: props.contextWindowLocked
            ? strings.contextWindowLocked
            : withFocusedInputTip(
                strings.contextWindowTitle,
                focusedField === 'contextWindow',
                strings.inputClearTip,
              ),
          padding: 0,
          style: boxStyle,
          clear: true,
        },
        () =>
          h(TInput, {
            x: 0,
            y: 0,
            w: Math.max(0, layout.contextWindowW - 2),
            h: layout.inputH,
            modelValue: props.contextWindow,
            'onUpdate:modelValue': props.contextWindowLocked
              ? () => {}
              : (v: string) => emit.updateContextWindow(v),
            placeholder: strings.contextWindowPlaceholder,
            ...commonInputProps,
            autoFocus: !props.contextWindowLocked,
            disabled: props.contextWindowLocked,
            plugins: props.contextWindowLocked ? [] : [numericPlugin],
            onFocus: () => emit.setFocusedField?.('contextWindow'),
            onBlur: () => emit.setFocusedField?.(null),
          }),
      ),

      // Row 2: Max Output Tokens + Temperature
      h(
        TBox,
        {
          x: 0,
          y: layout.maxTokensTemperatureY,
          w: layout.maxTokensW,
          h: layout.fieldBoxH,
          border: true,
          title: withFocusedInputTip(
            strings.maxTokensTitle,
            focusedField === 'maxTokens',
            strings.inputClearTip,
          ),
          padding: 0,
          style: boxStyle,
          clear: true,
        },
        () =>
          h(TInput, {
            x: 0,
            y: 0,
            w: Math.max(0, layout.maxTokensW - 2),
            h: layout.inputH,
            modelValue: props.maxTokens,
            'onUpdate:modelValue': (v: string) => emit.updateMaxTokens(v),
            placeholder: strings.maxTokensPlaceholder,
            ...commonInputProps,
            plugins: [numericPlugin],
            onFocus: () => emit.setFocusedField?.('maxTokens'),
            onBlur: () => emit.setFocusedField?.(null),
          }),
      ),
      h(
        TBox,
        {
          x: layout.maxTokensW + layout.colGap,
          y: layout.maxTokensTemperatureY,
          w: layout.temperatureW,
          h: layout.fieldBoxH,
          border: true,
          title: withFocusedInputTip(
            strings.temperatureTitle,
            focusedField === 'temperature',
            strings.inputClearTip,
          ),
          padding: 0,
          style: boxStyle,
          clear: true,
        },
        () =>
          h(TInput, {
            x: 0,
            y: 0,
            w: Math.max(0, layout.temperatureW - 2),
            h: layout.inputH,
            modelValue: props.temperature,
            'onUpdate:modelValue': (v: string) => emit.updateTemperature(v),
            placeholder: strings.temperaturePlaceholder,
            ...commonInputProps,
            plugins: [temperaturePlugin],
            onValidationError: (info: unknown) => {
              if (!info || typeof info !== 'object') return
              const plugin = (info as any).plugin
              if (plugin !== 'temperatureNumeric') return
              props.showToast?.(strings.temperatureValidationError)
            },
            onFocus: () => emit.setFocusedField?.('temperature'),
            onBlur: () => emit.setFocusedField?.(null),
          }),
      ),

      // Interleaved Thinking
      h(
        TBox,
        {
          x: 0,
          y: layout.interleavedThinkingY,
          w: layout.innerW,
          h: layout.interleavedThinkingH,
          border: true,
          title: props.interleavedThinkingLocked
            ? strings.interleavedThinkingLocked
            : strings.interleavedThinkingTitle,
          padding: 0,
          style: boxStyle,
          clear: true,
        },
        () =>
          h(TSelect, {
            x: 0,
            y: 0,
            w: Math.max(0, layout.innerW - 2),
            h: layout.interleavedInputH,
            options: [
              strings.interleavedThinkingOpen,
              strings.interleavedThinkingClose,
            ],
            multiple: true,
            multipleEmit: 'index',
            modelValue: [props.interleavedThinking ? 0 : 1],
            'onUpdate:modelValue': props.interleavedThinkingLocked
              ? () => {}
              : (v: number | number[]) => {
                  emit.updateInterleavedThinking(
                    nextInterleavedThinkingValue(props.interleavedThinking, v),
                  )
                },
            disabled: props.interleavedThinkingLocked,
            style: fieldStyle,
            highlightStyle: selectHighlightStyle,
            zIndex: 1002,
          }),
      ),
      layout.showShortcuts
        ? h(
            TBox,
            {
              x: 0,
              y: layout.shortcutsY,
              w: layout.innerW,
              h: layout.shortcutsH,
              border: true,
              title: withFocusedInputTip(
                strings.shortcutsTitle,
                isShortcutFocused,
                strings.inputClearTip,
              ),
              padding: 0,
              style: boxStyle,
              clear: true,
            },
            () => [
              h(TText, {
                x: 0,
                y: 0,
                w: shortcutLabelW,
                value: shortcutLabels[0],
                style: hintStyle,
              }),
              h(TInput, {
                x: shortcutInputX,
                y: 0,
                w: shortcutInputW,
                h: 1,
                modelValue: props.shortcutCommands,
                'onUpdate:modelValue': (v: string) =>
                  emit.updateShortcutCommands(v),
                placeholder: strings.shortcutsPlaceholder,
                ...commonInputProps,
                onFocus: () => emit.setFocusedField?.('shortcutCommands'),
                onBlur: () => emit.setFocusedField?.(null),
              }),
              h(TText, {
                x: 0,
                y: 1,
                w: shortcutLabelW,
                value: shortcutLabels[1],
                style: hintStyle,
              }),
              h(TInput, {
                x: shortcutInputX,
                y: 1,
                w: shortcutInputW,
                h: 1,
                modelValue: props.shortcutTimeline,
                'onUpdate:modelValue': (v: string) =>
                  emit.updateShortcutTimeline(v),
                placeholder: strings.shortcutsPlaceholder,
                ...commonInputProps,
                onFocus: () => emit.setFocusedField?.('shortcutTimeline'),
                onBlur: () => emit.setFocusedField?.(null),
              }),
              h(TText, {
                x: 0,
                y: 2,
                w: shortcutLabelW,
                value: shortcutLabels[2],
                style: hintStyle,
              }),
              h(TInput, {
                x: shortcutInputX,
                y: 2,
                w: shortcutInputW,
                h: 1,
                modelValue: props.shortcutNewSession,
                'onUpdate:modelValue': (v: string) =>
                  emit.updateShortcutNewSession(v),
                placeholder: strings.shortcutsPlaceholder,
                ...commonInputProps,
                onFocus: () => emit.setFocusedField?.('shortcutNewSession'),
                onBlur: () => emit.setFocusedField?.(null),
              }),
              layout.shortcutsHintY >= 0
                ? h(TText, {
                    x: 0,
                    y: layout.shortcutsHintY,
                    w: Math.max(0, layout.innerW - 2),
                    value: strings.shortcutsHint,
                    style: hintStyle,
                  })
                : null,
            ],
          )
        : null,
    ],
  )
}
