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

export type ToolSettingsDialogProps = Readonly<{
  modelValue: boolean
  w: number
  h: number
  backdrop?: boolean
  title?: string
  apiKeyDraft: string
  apiKeyMasked: string
  focusedField?: 'apiKey' | null
}>

export type ToolSettingsDialogEmits = Readonly<{
  updateModelValue: (v: boolean) => void
  updateApiKeyDraft: (v: string) => void
  setFocusedField?: (v: 'apiKey' | null) => void
  apply: () => void
  cancel: () => void
}>

type KeydownEventLike = Readonly<{
  key?: string
  preventDefault?: () => void
  stopPropagation?: () => void
}>

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

const stripMultilinePlugin = createTextRestrictionPlugin({
  name: 'toolSettingsSingleLine',
  rules: [{ replace: { from: /[\r\n]+/g, to: '' } }],
})

export function renderToolSettingsDialog(
  props: ToolSettingsDialogProps,
  emit: ToolSettingsDialogEmits,
  ui: UiThemeContext,
): VNode | null {
  if (!props.modelValue) return null

  const layout = computeToolSettingsDialogLayout({
    w: props.w,
    h: props.h,
    apiKeyMasked: props.apiKeyMasked,
  })
  const strings = getToolSettingsDialogStrings()

  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 faintStyle = ui.style(['dialog.chrome', 'text.faint'])
  const boxStyle = ui.style(['dialog.chrome', 'dialog.chrome'])
  const fieldStyle = ui.style(['input.field'], dialogBgStyle)

  const commonInputProps = {
    cursorToEndOnFirstFocus: true,
    cursorToEndOnExternalUpdate: true,
    style: fieldStyle,
    zIndex: 1002,
  } as const

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

  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: props.title ?? strings.title,
      placement: 'center',
      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(),
    },
    () => [
      h(TText, {
        x: 0,
        y: 0,
        w: layout.innerW,
        h: layout.contentH,
        value: '',
        style: bodyStyle,
      }),
      topHintNode,
      layout.canShowCurrentLine
        ? h(TText, {
            x: 0,
            y: layout.apiKeyHintY,
            w: layout.innerW,
            value: props.apiKeyMasked
              ? `${strings.apiKeyCurrentPrefix} ${props.apiKeyMasked}`
              : `${strings.apiKeyCurrentPrefix} ${strings.apiKeyNotSet}`,
            style: faintStyle,
          })
        : null,
      h(
        TBox,
        {
          x: 0,
          y: layout.apiKeyY,
          w: layout.innerW,
          h: layout.fieldBoxH,
          border: true,
          title: withFocusedInputTip(
            strings.websearchTitle,
            props.focusedField === 'apiKey',
            strings.inputClearTip,
          ),
          padding: 0,
          style: boxStyle,
          clear: true,
        },
        () =>
          h(TInput, {
            x: 0,
            y: 0,
            w: Math.max(0, layout.innerW - 2),
            h: layout.inputH,
            modelValue: props.apiKeyDraft,
            'onUpdate:modelValue': (v: string) => emit.updateApiKeyDraft(v),
            placeholder: strings.apiKeyPlaceholder,
            secret: true,
            plugins: [stripMultilinePlugin],
            ...commonInputProps,
            autoFocus: true,
            onFocus: () => emit.setFocusedField?.('apiKey'),
            onBlur: () => emit.setFocusedField?.(null),
          }),
      ),
    ],
  )
}
