import {
  GaugeContainer,
  GaugeSvg,
  GaugeValue,
  VitalCard,
  VitalLabel,
  VitalsSection,
} from '../styles'
import { update } from '../update'

interface AppMetrics {
  cpu: number
  mem: number
  disk: number
}

interface SystemMetrics {
  cpu: number
  ram: { used: number, total: number, percent: number }
  disk: { used: number, total: number, percent: number }
  apps: Record<string, AppMetrics>
}

const SEGMENTS = 19
const START_ANGLE = -225
const END_ANGLE = 45
const SWEEP = END_ANGLE - START_ANGLE
const CX = 60
const CY = 60
const RADIUS = 44
const SEGMENT_GAP = 3
const SEGMENT_WIDTH = 8
const NEEDLE_LENGTH = 38

let _metrics: SystemMetrics = {
  cpu: 0,
  ram: { used: 0, total: 0, percent: 0 },
  disk: { used: 0, total: 0, percent: 0 },
  apps: {},
}
let _source: EventSource | undefined

const formatBytes = (bytes: number): string => {
  if (bytes < 1024) return `${bytes}B`
  if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)}K`
  if (bytes < 1024 * 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))}M`
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}G`
}

function updateTooltips(apps: Record<string, AppMetrics>) {
  for (const [name, m] of Object.entries(apps)) {
    document.querySelectorAll(`[data-app="${name}"]`).forEach(dot => {
      const parent = dot.parentElement
      if (parent?.hasAttribute('data-tooltip')) {
        parent.setAttribute('data-tooltip',
          `${name}\n${'─'.repeat(name.length)}\nCPU  ${m.cpu}%\nMEM  ${formatBytes(m.mem)}\nDISK ${formatBytes(m.disk)}`)
      }
    })
  }
}

const toRad = (deg: number) => (deg * Math.PI) / 180

const segmentColor = (i: number, total: number): string => {
  const t = i / (total - 1)
  if (t < 0.4) return '#4caf50'
  if (t < 0.6) return '#8bc34a'
  if (t < 0.75) return '#ffc107'
  if (t < 0.9) return '#ff9800'
  return '#f44336'
}

function Gauge({ value }: { value: number }) {
  const segmentSweep = SWEEP / SEGMENTS
  const activeSegments = Math.round((value / 100) * SEGMENTS)

  const segments = []
  for (let i = 0; i < SEGMENTS; i++) {
    const startDeg = START_ANGLE + i * segmentSweep + SEGMENT_GAP / 2
    const endDeg = START_ANGLE + (i + 1) * segmentSweep - SEGMENT_GAP / 2
    const innerR = RADIUS - SEGMENT_WIDTH / 2
    const outerR = RADIUS + SEGMENT_WIDTH / 2

    const x1 = CX + outerR * Math.cos(toRad(startDeg))
    const y1 = CY + outerR * Math.sin(toRad(startDeg))
    const x2 = CX + outerR * Math.cos(toRad(endDeg))
    const y2 = CY + outerR * Math.sin(toRad(endDeg))
    const x3 = CX + innerR * Math.cos(toRad(endDeg))
    const y3 = CY + innerR * Math.sin(toRad(endDeg))
    const x4 = CX + innerR * Math.cos(toRad(startDeg))
    const y4 = CY + innerR * Math.sin(toRad(startDeg))

    const color = i < activeSegments ? segmentColor(i, SEGMENTS) : 'var(--colors-border)'

    segments.push(
      <path
        key={i}
        d={`M ${x1} ${y1} A ${outerR} ${outerR} 0 0 1 ${x2} ${y2} L ${x3} ${y3} A ${innerR} ${innerR} 0 0 0 ${x4} ${y4} Z`}
        fill={color}
      />
    )
  }

  // Needle
  const needleAngle = START_ANGLE + (value / 100) * SWEEP
  const nx = CX + NEEDLE_LENGTH * Math.cos(toRad(needleAngle))
  const ny = CY + NEEDLE_LENGTH * Math.sin(toRad(needleAngle))
  // Needle base width
  const perpAngle = needleAngle + 90
  const bw = 3
  const bx1 = CX + bw * Math.cos(toRad(perpAngle))
  const by1 = CY + bw * Math.sin(toRad(perpAngle))
  const bx2 = CX - bw * Math.cos(toRad(perpAngle))
  const by2 = CY - bw * Math.sin(toRad(perpAngle))

  return (
    <GaugeContainer>
      <GaugeSvg viewBox="10 10 100 55">
        {segments}
        <polygon points={`${nx},${ny} ${bx1},${by1} ${bx2},${by2}`} fill="var(--colors-text)" />
        <circle cx={CX} cy={CY} r="4" fill="var(--colors-textMuted)" />
      </GaugeSvg>
      <GaugeValue>{value}%</GaugeValue>
    </GaugeContainer>
  )
}

function VitalsContent() {
  return (
    <>
      <VitalCard>
        <VitalLabel>CPU</VitalLabel>
        <Gauge value={_metrics.cpu} />
      </VitalCard>
      <VitalCard>
        <VitalLabel>RAM</VitalLabel>
        <Gauge value={_metrics.ram.percent} />
      </VitalCard>
      <VitalCard>
        <VitalLabel>Disk</VitalLabel>
        <Gauge value={_metrics.disk.percent} />
      </VitalCard>
    </>
  )
}

export function initVitals() {
  if (_source) return
  _source = new EventSource('/api/system/metrics/stream')
  _source.onmessage = e => {
    try {
      _metrics = JSON.parse(e.data)
      update('#vitals', <VitalsContent />)
      updateTooltips(_metrics.apps)
    } catch {}
  }
}

export function Vitals() {
  return (
    <VitalsSection id="vitals">
      <VitalsContent />
    </VitalsSection>
  )
}
