import type { Client } from 'ssh2'
import { execCommand, toFixedNum } from './common.js'

function parseCpuLine(cpuLine: string): { total: number; idle: number } | undefined {
  const parts = cpuLine.trim().split(/\s+/).slice(1).map(Number)
  if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return undefined
  const idle = parts[3] + (parts[4] ?? 0)
  const total = parts.reduce((sum, n) => sum + n, 0)
  return { total, idle }
}

export async function collectCpuMetrics(
  client: Client,
): Promise<{ percent: number | null; cores: number | null; load: [number, number, number] | null }> {
  let percent: number | null = null
  let cores: number | null = null
  let load: [number, number, number] | null = null

  try {
    const work = (async () => {
      const first = await execCommand(client, "grep '^cpu ' /proc/stat")
      await new Promise((r) => setTimeout(r, 500))
      const [second, loadOut, coresOut] = await Promise.all([
        execCommand(client, "grep '^cpu ' /proc/stat"),
        execCommand(client, 'cat /proc/loadavg'),
        execCommand(client, 'nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo'),
      ])

      const a = parseCpuLine(first.stdout)
      const b = parseCpuLine(second.stdout)
      if (a && b) {
        const totalDiff = b.total - a.total
        const idleDiff = b.idle - a.idle
        if (totalDiff > 0) {
          percent = toFixedNum(Math.min(100, Math.max(0, ((totalDiff - idleDiff) / totalDiff) * 100)))
        }
      }

      const loadParts = loadOut.stdout.trim().split(/\s+/).slice(0, 3).map(Number)
      if (loadParts.length === 3 && loadParts.every(Number.isFinite)) {
        load = loadParts as [number, number, number]
      }

      const coreCount = Number(coresOut.stdout.trim())
      cores = Number.isFinite(coreCount) ? coreCount : null
    })()

    await Promise.race([work, new Promise((_, reject) => setTimeout(() => reject(new Error('cpu metrics timeout')), 25000))])
  } catch {
    // best-effort; leave nulls
  }

  return { percent, cores, load }
}
