<template>
  <div class="hud-metrics">
    <button v-if="groups.length" class="metrics-copy-btn" @click="copyAll">
      <ClipboardDocumentIcon v-if="!copied" class="w-3 h-3" />
      <CheckIcon v-else class="w-3 h-3" />
    </button>
    <div v-for="group in groups" :key="group.label" class="metric-group">
      <span
        v-for="item in group.items" :key="item.key"
        class="m"
        @click="copyToClipboard(item.title)"
        @mouseenter="(e) => showTooltip(item.key, e)"
        @mouseleave="activeTooltip = null"
      >{{ item.key }}: <b>{{ item.value }}</b>
      </span>
    </div>
    <!-- Tooltip rendered via Teleport → body, uses fixed positioning to avoid overflow -->
    <Teleport to="body">
      <div
        v-if="activeTooltip"
        class="metric-tooltip"
        :style="{ top: tooltipY + 'px', left: tooltipX + 'px' }"
      >{{ groups.flatMap(g => g.items).find(i => i.key === activeTooltip)?.title }}</div>
    </Teleport>
  </div>
</template>

<script setup lang="ts">
import { computed, watch, ref } from 'vue'
import { ClipboardDocumentIcon, CheckIcon } from '@heroicons/vue/20/solid'

const props = defineProps({
  usage: Object,
  finance: Object,
  selectedAgent: String,
  allAgents: Array as () => any[],
})

const agent = computed(() => props.allAgents?.find((a: any) => a.id === props.selectedAgent))
const inn = computed(() => Number(props.usage?.input_tokens ?? props.usage?.in ?? 0))
const out = computed(() => Number(props.usage?.output_tokens ?? props.usage?.out ?? 0))

const sessionCost = computed(() => {
  const a = agent.value
  if (!a || a.promptPrice == null || a.completionPrice == null) return 0
  return (inn.value * a.promptPrice + out.value * a.completionPrice) / 1_000_000
})

const lastTurnCost = ref(0)
const lstHistory = ref<number[]>([]) // ring buffer, last 5 LST values

watch(sessionCost, (newVal, oldVal) => {
  const delta = newVal - oldVal
  if (delta > 0.000001) {
    lastTurnCost.value = delta
    lstHistory.value = [...lstHistory.value.slice(-4), delta] // keep last 5
  }
})

const trend = computed(() => {
  const h = lstHistory.value
  if (h.length < 2) return null
  // slope = average delta between consecutive values
  let sum = 0
  for (let i = 1; i < h.length; i++) sum += h[i] - h[i - 1]
  return sum / (h.length - 1)
})

const trendTitle = computed(() => {
  const h = lstHistory.value
  if (h.length < 2) {
    const needed = 2 - h.length
    return `Trend not available yet.\nNeeds at least 2 completed turns to compute slope.\nCurrently have: ${h.length} turn${h.length === 1 ? '' : 's'}.\nWill appear after ${needed} more turn${needed === 1 ? '' : 's'}.`
  }
  const vals = h.map((v, i) => {
    const delta = i === 0 ? '' : ` (${h[i] - h[i-1] >= 0 ? '+' : ''}$${(h[i] - h[i-1]).toFixed(6)})`
    return `  turn -${h.length - 1 - i}: $${v.toFixed(6)}${delta}`
  }).join('\n')
  const t = trend.value!
  return `Source: rolling slope of last ${h.length} LST values\nFormula: avg(LST[i] - LST[i-1]) over last ${h.length} turns\nMeaning: ${t >= 0 ? 'Cost per turn is growing' : 'Cost per turn is shrinking'} (context ${t >= 0 ? 'expanding' : 'stabilising'})\nHistory:\n${vals}\nSlope: ${t >= 0 ? '+' : ''}$${t.toFixed(6)}/turn`
})

const groups = computed(() => {
  const result = []
  const a = agent.value
  const f = props.finance

  if (props.usage) {
    result.push({
      label: 'tokens',
      items: [
        {
          key: 'IN',
          value: formatTokens(inn.value),
          title: `Source: session_total_tokens (session-watcher.js, cumulative)\nMeaning: Total input tokens sent to the model this session (context window grows each turn)\nRaw: ${inn.value.toLocaleString()} tokens`
        },
        {
          key: 'OUT',
          value: formatTokens(out.value),
          title: `Source: session_total_tokens (session-watcher.js, cumulative)\nMeaning: Total output tokens generated by the model this session\nRaw: ${out.value.toLocaleString()} tokens`
        },
      ]
    })
  }

  if (sessionCost.value > 0.00001) {
    const costItems = []
    if (sessionCost.value > 0.00001) {
      costItems.push({
        key: 'TOT',
        value: `$${sessionCost.value.toFixed(4)}`,
        title: a
          ? `Source: IN/OUT tokens × agent pricing from allAgents (OpenRouter model list)\nFormula: (IN × $${(a.promptPrice ?? 0).toFixed(2)}/1M) + (OUT × $${(a.completionPrice ?? 0).toFixed(2)}/1M)\nModel: ${a.modelName || a.model}\nUsage: ${inn.value.toLocaleString()} in + ${out.value.toLocaleString()} out = ${(inn.value + out.value).toLocaleString()} tokens\nTotal: $${sessionCost.value.toFixed(6)}`
          : `Source: IN/OUT tokens (pricing unavailable)\nTotal: $${sessionCost.value.toFixed(6)}`
      })
    }

    if (lastTurnCost.value > 0) {
      costItems.push({
        key: 'LST',
        value: `$${lastTurnCost.value.toFixed(4)}`,
        title: `Source: TOT delta (frontend-computed, updates when sessionCost changes)\nFormula: TOT_after - TOT_before for the last completed turn\nMeaning: True cost of the last turn including full context window\nDelta: $${lastTurnCost.value.toFixed(6)}`
      })
    }
    const t = trend.value
    costItems.push({
      key: 'TRD',
      value: lstHistory.value.length < 2 ? 'n/a' : `${t! >= 0 ? '+' : ''}$${t!.toFixed(4)}`,
      title: trendTitle.value
    })
    if (costItems.length) result.push({ label: 'cost', items: costItems })
  }

  return result
})

const allText = computed(() =>
  groups.value.flatMap(g => g.items.map(i => `${i.key}: ${i.value}\n${i.title}`)).join('\n\n')
)

const copied = ref(false)
const activeTooltip = ref<string | null>(null)
const tooltipX = ref(0)
const tooltipY = ref(0)

function showTooltip(key: string, e: MouseEvent) {
    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    tooltipX.value = Math.min(rect.left, window.innerWidth - 360);
    tooltipY.value = rect.top - 8; // will be pushed up by transform in CSS
    activeTooltip.value = key;
}
function copyAll() {
  const text = allText.value
  navigator.clipboard.writeText(text).then(() => {
    copied.value = true
    setTimeout(() => copied.value = false, 2000)
  }).catch(() => {})
}

function copyToClipboard(val: string) {
  navigator.clipboard.writeText(val).catch(() => {})
}

function formatTokens(t: number) {
  return t >= 1000 ? (t / 1000).toFixed(1) + 'k' : String(t)
}
</script>

<style scoped>
.hud-metrics {
  display: flex;
  flex: 1;
  width: 100%;
  min-width: 200px;
  height: 100%;
  box-sizing: border-box;
  flex-direction: column;
  gap: 0.4rem;
  align-items: stretch;
  background: rgba(34, 197, 94, 0.05);
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  position: relative;
}
.metric-group {
  display: flex;
  gap: 0.75rem;
  font-size: var(--text-base);
  color: var(--text-dim);
  }
.m { cursor: copy; position: relative; }
.m b { color: var(--text); font-weight: 700; margin-left: 2px; }
.metric-tooltip {
  position: fixed;
  transform: translateY(-100%);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem 0.65rem;
  font-size: var(--text-base);
  color: var(--text-dim);
  white-space: pre-wrap;
  line-height: 1.6;
  z-index: 9999;
  pointer-events: none;
  box-shadow: 0 4px 16px rgba(0,0,0,0.4);
  min-width: 220px;
  max-width: 340px;
}
.metrics-copy-btn {
  position: absolute;
  top: 4px;
  right: 6px;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: var(--text-base);
  padding: 0;
  cursor: pointer;
  opacity: 0.4;
  transition: opacity 0.15s;
  font-family: var(--font-mono);
  line-height: 1;
}
.metrics-copy-btn:hover { opacity: 1; }
</style>
