import type { DimSdkSessionTrace } from '../../keys'
import type { PropType } from 'vue'
import { t } from '#cli/i18n'
import { TDialog, TSelect, TText, wrapByCells } from '@simon_he/vue-tui'
import { defineComponent, h } from 'vue'
import { useUiTheme } from '../theme'
import { clamp } from '../utils/math'

function formatClockTime(ms?: number): string {
  if (!ms || !Number.isFinite(ms))
    return ''
  const date = new Date(ms)
  const hh = String(date.getHours()).padStart(2, '0')
  const mm = String(date.getMinutes()).padStart(2, '0')
  const ss = String(date.getSeconds()).padStart(2, '0')
  return `${hh}:${mm}:${ss}`
}

function requestLabel(
  request: NonNullable<DimSdkSessionTrace>['requests'][number],
): string {
  if (request.kind === 'session')
    return `S#${request.index} ${t('chatPage.trace.sessionEvents')}`
  return `R#${request.index} ${request.promptPreview || t('chatPage.trace.requestFallback')}`
}

function requestDetail(
  request: NonNullable<DimSdkSessionTrace>['requests'][number],
): string {
  const parts = [
    formatClockTime(request.startedAt),
    request.status,
    `${request.eventCount}e`,
    `${request.runCount}r`,
    `${request.toolCallCount}t`,
    `${request.childTaskCount}c`,
  ].filter(Boolean)
  if (request.compactionCount > 0)
    parts.push(`${request.compactionCount}cmp`)
  return parts.join(' · ')
}

function wrapTraceLines(
  lines: readonly string[],
  width: number,
  height: number,
): string {
  const wrapped = lines.flatMap((line) =>
    wrapByCells(String(line ?? ''), Math.max(1, width)),
  )
  return wrapped.slice(0, Math.max(0, height)).join('\n')
}

export const DimSdkSessionTraceDialog = defineComponent({
  name: 'DimSdkSessionTraceDialog',
  props: {
    modelValue: { type: Boolean, required: true },
    w: { type: Number, required: true },
    h: { type: Number, required: true },
    trace: {
      type: Object as PropType<DimSdkSessionTrace | null>,
      default: null,
    },
    loading: { type: Boolean, default: false },
    error: { type: String, default: '' },
    selectedIndex: { type: Number, default: 0 },
  },
  emits: {
    'update:modelValue': (_v: boolean) => true,
    'update:selectedIndex': (_v: number) => true,
    copy: () => true,
    refresh: () => true,
  },
  setup(props, { emit }) {
    const ui = useUiTheme()

    return () => {
      if (!props.modelValue)
        return null

      const dialogW = Math.max(60, Math.floor(props.w))
      const dialogH = Math.max(18, Math.floor(props.h))
      const innerW = Math.max(0, dialogW - 4)
      const innerH = Math.max(0, dialogH - 4)
      const listY = 2
      const listH = clamp(Math.floor(innerH * 0.36), 4, Math.max(4, innerH - 8))
      const detailY = listY + listH + 1
      const detailH = Math.max(4, innerH - detailY - 1)
      const options = (props.trace?.requests ?? []).map(request => ({
        detail: requestDetail(request),
        label: requestLabel(request),
      }))
      const selected = (props.trace?.requests ?? [])[
        clamp(props.selectedIndex, 0, Math.max(0, options.length - 1))
      ]
      const lines = (() => {
        if (props.loading)
          return [t('chatPage.trace.loading')]
        if (props.error)
          return [t('chatPage.trace.error'), props.error]
        if (!selected)
          return [t('chatPage.trace.empty')]

        const detailLines = [
          selected.kind === 'session'
            ? t('chatPage.trace.sessionEvents')
            : `${requestLabel(selected)} · ${selected.status}`,
          ...(selected.turnId ? [`Turn: ${selected.turnId}`] : []),
          ...(selected.promptPreview ? [`Prompt: ${selected.promptPreview}`] : []),
          ...(selected.assistantPreview ? [`Assistant: ${selected.assistantPreview}`] : []),
          t('chatPage.trace.counts', {
            children: selected.childTaskCount,
            compactions: selected.compactionCount,
            events: selected.eventCount,
            runs: selected.runCount,
            tools: selected.toolCallCount,
          }),
          'Events:',
        ]
        const remaining = Math.max(0, detailH - detailLines.length - 1)
        const visibleEvents = selected.events.slice(0, remaining)
        detailLines.push(
          ...visibleEvents.map(event =>
            `${formatClockTime(event.at) || '··:··:··'} #${event.sequence} ${event.type} · ${event.summary}`,
          ),
        )
        if (selected.events.length > visibleEvents.length) {
          detailLines.push(
            t('chatPage.trace.moreEvents', {
              count: selected.events.length - visibleEvents.length,
            }),
          )
        }
        return detailLines
      })()
      const summary = props.trace
        ? t('chatPage.trace.summary', {
            events: props.trace.eventCount,
            requests: props.trace.requests.length,
          })
        : ''

      return h(
        TDialog as any,
        {
          modelValue: props.modelValue,
          'onUpdate:modelValue': (v: boolean) => emit('update:modelValue', v),
          onKeydownCapture: (e: any) => {
            if (e?.key === 'Escape') {
              e.preventDefault?.()
              e.stopPropagation?.()
              emit('update:modelValue', false)
            }
          },
          w: dialogW,
          h: dialogH,
          title: t('chatPage.trace.title'),
          placement: 'center',
          backdrop: false,
          padding: 1,
          style: ui.style(['dialog.chrome']),
          closeOnConfirm: false,
          buttons: [
            { label: t('common.copy'), value: 'copy' },
            { label: t('common.refresh'), value: 'refresh' },
            { label: t('common.close'), value: 'close', kind: 'primary' },
          ],
          onConfirm: (btn: any) => {
            if (btn?.value === 'copy') {
              emit('copy')
              return
            }
            if (btn?.value === 'refresh') {
              emit('refresh')
              return
            }
            emit('update:modelValue', false)
          },
          onClose: () => emit('update:modelValue', false),
        },
        () => [
          h(TText, {
            x: 0,
            y: 0,
            w: innerW,
            value: summary,
            style: ui.style(['dialog.chrome', 'text.muted']),
          }),
          h(TText, {
            x: 0,
            y: 1,
            w: innerW,
            value: t('chatPage.trace.hint'),
            style: ui.style(['dialog.chrome', 'text.muted']),
          }),
          options.length
            ? h(TSelect, {
                x: 0,
                y: listY,
                w: innerW,
                h: listH,
                options: options as any,
                modelValue: clamp(
                  props.selectedIndex,
                  0,
                  Math.max(0, options.length - 1),
                ),
                'onUpdate:modelValue': (v: number) =>
                  emit(
                    'update:selectedIndex',
                    clamp(v, 0, Math.max(0, options.length - 1)),
                  ),
                autoFocus: true,
                style: ui.style(['dialog.chrome', 'text.primary']),
                highlightStyle: ui.style(['select.item']),
                zIndex: 5,
              })
            : h(TText, {
                x: 0,
                y: listY,
                w: innerW,
                h: listH,
                value: props.loading
                  ? t('chatPage.trace.loading')
                  : props.error
                    ? t('chatPage.trace.error')
                    : t('chatPage.trace.empty'),
                style: ui.style(['dialog.chrome', 'text.muted']),
              }),
          h(TText, {
            x: 0,
            y: detailY,
            w: innerW,
            h: detailH,
            wrap: true,
            value: wrapTraceLines(lines, innerW, detailH),
            style: ui.style(['dialog.chrome', 'text.primary']),
          }),
        ],
      )
    }
  },
})
