import type { AnsiColorName } from '@simon_he/vue-tui'
import type { UiThemeContext } from '../../ui/theme'
import {
  padEndByCells,
  sliceByCells,
  spaces,
  textCellWidth,
  TText,
  TView,
  wrapByCells,
} from '@simon_he/vue-tui'
import { h } from 'vue'

type UpgradeNotification = Readonly<{
  visible: boolean
  message: string
}>

export function renderUpgradeToastOverlay(
  opts: Readonly<{
    notification?: UpgradeNotification | null
    cols: number
    ui?: UiThemeContext
    onDismiss?: () => void
    onFocus?: () => void
  }>,
): any[] {
  const nodes: any[] = []

  const notification = opts.notification
  if (!notification?.visible) {
    return nodes
  }

  const message = String(notification.message ?? '').trim()
  if (!message) {
    return nodes
  }

  const variant = message.startsWith('Update available')
    ? 'update'
    : message.startsWith('Update installed') || message.startsWith('No updates')
      ? 'ok'
      : message.startsWith('Auto-update failed') ||
          message.startsWith('Update check failed')
        ? 'error'
        : 'info'

  // Use dark text on light backgrounds, light text on dark backgrounds
  const isLightTheme =
    opts.ui?.palette?.whiteBright === '#ffffff' &&
    opts.ui?.palette?.blackBright === '#f3f3f3'
  const fg: AnsiColorName = isLightTheme ? 'black' : 'whiteBright'

  // Match the app toast style (dark background with side bars).
  const bg: AnsiColorName = 'blackBright'
  const accentBg: AnsiColorName =
    variant === 'error'
      ? 'redBright'
      : variant === 'ok'
        ? 'greenBright'
        : 'cyanBright'

  const barW = 1
  const paddingX = 3
  const paddingY = 1

  const safeCols = Math.max(0, Math.floor(opts.cols ?? 0))
  const maxToastW = Math.max(22, Math.min(56, safeCols - 4))
  const minToastW = Math.min(28, maxToastW)

  const rawLines = message.replace(/\r/g, '').split('\n')
  const longestLineW = rawLines.reduce(
    (acc, line) => Math.max(acc, textCellWidth(line)),
    0,
  )
  const baseWidth = longestLineW + barW * 2 + paddingX * 2
  const toastW = Math.min(Math.max(baseWidth, minToastW), maxToastW)
  const contentW = Math.max(1, toastW - barW * 2 - paddingX * 2)

  const maxLines = 3
  let lines = [...wrapByCells(message, contentW)]
  if (lines.length > maxLines) {
    lines = lines.slice(0, maxLines)
    const lastIndex = maxLines - 1
    if (contentW > 1) {
      lines[lastIndex] = `${sliceByCells(lines[lastIndex], contentW - 1)}…`
    } else {
      lines[lastIndex] = '…'
    }
  }

  const alignedLines = lines.map((line) => {
    const clipped = sliceByCells(line, contentW)
    return padEndByCells(clipped, contentW)
  })

  const toastH = Math.max(1, lines.length) + paddingY * 2
  const toastX = Math.max(2, safeCols - toastW - 2)
  const toastY = 1 // Just below the top edge

  nodes.push(
    h(TText, {
      key: 'upgrade-toast-bg',
      x: toastX,
      y: toastY,
      w: toastW,
      h: toastH,
      value: spaces(toastW),
      style: { bg },
      zIndex: 200,
    }),

    h(TText, {
      key: 'upgrade-toast-accent-left',
      x: toastX,
      y: toastY,
      w: barW,
      h: toastH,
      value: spaces(barW),
      style: { bg: accentBg },
      zIndex: 201,
    }),

    h(TText, {
      key: 'upgrade-toast-text',
      x: toastX + barW + paddingX,
      y: toastY + paddingY,
      w: contentW,
      h: lines.length,
      value: alignedLines.join('\n'),
      style: { fg, bg, bold: true },
      zIndex: 202,
    }),
  )

  nodes.push(
    h(TText, {
      key: 'upgrade-toast-accent-right',
      x: toastX + toastW - barW,
      y: toastY,
      w: barW,
      h: toastH,
      value: spaces(barW),
      style: { bg: accentBg },
      zIndex: 201,
    }),
  )

  nodes.push(
    h(TView, {
      key: 'upgrade-toast-hit',
      x: toastX,
      y: toastY,
      w: toastW,
      h: toastH,
      zIndex: 210,
      focusable: false,
      onClick: () => {
        opts.onDismiss?.()
        opts.onFocus?.()
      },
    }),
  )

  return nodes
}
