import type { VNode } from 'vue'
import type { UiThemeContext } from '../../theme'
import { TDialog, TText } from '@simon_he/vue-tui'
import { h } from 'vue'
import { formatMcpStatusLines } from './logic'
import {
  computeMcpSettingsDialogLayout,
  getMcpSettingsDialogStrings,
} from './view-model'

export type McpSettingsDialogProps = Readonly<{
  modelValue: boolean
  w: number
  h: number
  backdrop?: boolean
  mcpJsonFilePath: string
  serverCount: number
  testStatus: {
    state: 'idle' | 'testing' | 'success' | 'error'
    message?: string
    results?: ReadonlyArray<{
      name: string
      toolCount?: number
      error?: string
      disabled?: boolean
    }>
  }
}>

export type McpSettingsDialogEmits = Readonly<{
  updateModelValue: (v: boolean) => void
  openFile: () => void
  reload: () => void
  test: () => void
  close: () => void
}>

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

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

const EXAMPLE_JSON = `{
  "mcpServers": [
    {
      "name": "my-server",
      "transport": "stdio",
      "command": "npx",
      "args": ["-y", "@my/mcp-server"],
      "enabled": true
    }
  ]
}`

export function renderMcpSettingsDialog(
  props: McpSettingsDialogProps,
  emit: McpSettingsDialogEmits,
  ui: UiThemeContext,
): VNode | null {
  if (!props.modelValue) return null

  const layout = computeMcpSettingsDialogLayout({ w: props.w, h: props.h })
  const strings = getMcpSettingsDialogStrings()

  const chromeStyle = ui.style(['dialog.chrome'])
  const bodyStyle = chromeStyle
  const hintStyle = ui.style(['dialog.chrome', 'text.muted'])
  const labelStyle = ui.style(['dialog.chrome', 'text.primary'], { bold: true })
  const pathStyle = ui.style(['dialog.chrome', 'text.accent'])

  // Build status lines for test results
  const statusLines = formatMcpStatusLines(
    props.testStatus,
    { state: 'idle' },
    strings,
  )

  const nodes: VNode[] = []

  // Background fill
  nodes.push(
    h(TText, {
      x: 0,
      y: 0,
      w: layout.innerW,
      h: layout.innerH,
      value: '',
      style: bodyStyle,
    }),
  )

  let y = 0

  // Hint line
  if (layout.showHint) {
    nodes.push(
      h(TText, {
        x: 0,
        y,
        w: layout.innerW,
        value: strings.hint,
        style: hintStyle,
      }),
    )
    y += 1
  }

  // Config file label
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      value: strings.configFileLabel,
      style: labelStyle,
    }),
  )
  y += 1

  // File path
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      value: props.mcpJsonFilePath || '~/.dimcode/mcp.json',
      style: pathStyle,
    }),
  )
  y += 2

  // Server count
  const countText = props.serverCount > 0
    ? strings.serverCount.replace('{count}', String(props.serverCount))
    : strings.noServersHint
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      value: countText,
      style: hintStyle,
    }),
  )
  y += 1

  // Guide text
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      value: strings.guideText,
      style: hintStyle,
    }),
  )
  y += 2

  // Example format
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      value: strings.exampleFormat,
      style: labelStyle,
    }),
  )
  y += 1

  const remainingH = Math.max(1, layout.contentH - y - (statusLines.length ? statusLines.length + 1 : 0))
  const exampleLines = EXAMPLE_JSON.split('\n')
  const displayExample = exampleLines.slice(0, remainingH).join('\n')
  nodes.push(
    h(TText, {
      x: 0,
      y,
      w: layout.innerW,
      h: Math.min(exampleLines.length, remainingH),
      value: displayExample,
      style: hintStyle,
    }),
  )
  y += Math.min(exampleLines.length, remainingH)

  // Status lines (test results) — cap to available space so they don't
  // overflow the content area and hide the dialog buttons.
  if (statusLines.length) {
    const maxStatusH = Math.max(0, layout.contentH - y - 1)
    if (maxStatusH > 0) {
      y += 1
      const displayStatus = statusLines.slice(0, maxStatusH)
      nodes.push(
        h(TText, {
          x: 0,
          y,
          w: layout.innerW,
          h: displayStatus.length,
          value: displayStatus.join('\n'),
          style: hintStyle,
        }),
      )
    }
  }

  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.close()
          emit.updateModelValue(false)
        }
      },
      w: layout.dialogW,
      h: layout.dialogH,
      title: strings.title,
      placement: 'center',
      backdrop: Boolean(props.backdrop),
      closeOnBackdrop: false,
      closeOnConfirm: false,
      padding: 1,
      style: chromeStyle,
      buttons: [
        {
          label: strings.openFile,
          value: 'open',
          kind: 'primary',
          default: true,
        },
        { label: strings.reload, value: 'reload' },
        { label: strings.test, value: 'test' },
        { label: strings.close, value: 'close' },
      ],
      onConfirm: (btn: ConfirmButtonLike | null | undefined) => {
        if (!btn?.value) return
        if (btn.value === 'open') emit.openFile()
        else if (btn.value === 'reload') emit.reload()
        else if (btn.value === 'test') emit.test()
        else emit.close()
      },
      onClose: () => emit.close(),
    },
    () => nodes,
  )
}
