import { formatDateTimeBeijing, parseApiDateTime } from '@/utils/datetime'
import type { SettingItem } from '@/types/api'

export interface FleetTrendAlertEntry {
  server_name: string
  server_id?: number
  alert_type: string
  alert_type_label?: string
  value: string
  is_recovery: boolean
  created_at?: string
}

export interface FleetTrendPoint {
  recorded_at: string
  online_count: number
  sample_count?: number
  cpu_avg: number | null
  mem_avg: number | null
  disk_avg: number | null
  alert_count?: number
  alerts?: FleetTrendAlertEntry[]
}

export interface MetricStats {
  current: number | null
  previous: number | null
  delta: number | null
  min: number | null
  max: number | null
  avg: number | null
}

export interface FleetAlertThresholds {
  cpu: number
  mem: number
  disk: number
}

export type FleetMetricKey = 'cpu' | 'mem' | 'disk' | 'online'

const METRIC_FIELDS: Record<FleetMetricKey, keyof FleetTrendPoint | null> = {
  cpu: 'cpu_avg',
  mem: 'mem_avg',
  disk: 'disk_avg',
  online: null,
}

export function metricValues(points: FleetTrendPoint[], key: FleetMetricKey): (number | null)[] {
  if (key === 'online') return points.map((p) => p.online_count)
  const field = METRIC_FIELDS[key]!
  return points.map((p) => p[field] as number | null)
}

export function computeMetricStats(values: (number | null)[]): MetricStats {
  const nums = values.filter((v): v is number => v != null)
  const current = values.length ? values[values.length - 1] : null
  const previous = values.length > 1 ? values[values.length - 2] : null
  const delta =
    current != null && previous != null ? Math.round((current - previous) * 10) / 10 : null
  if (!nums.length) {
    return { current, previous, delta, min: null, max: null, avg: null }
  }
  const sum = nums.reduce((a, b) => a + b, 0)
  return {
    current,
    previous,
    delta,
    min: Math.min(...nums),
    max: Math.max(...nums),
    avg: Math.round(sum / nums.length),
  }
}

export function computeRangeStats(
  points: FleetTrendPoint[],
  startIdx: number,
  endIdx: number,
): Record<FleetMetricKey, MetricStats> {
  const slice = points.slice(startIdx, endIdx + 1)
  return {
    cpu: computeMetricStats(metricValues(slice, 'cpu')),
    mem: computeMetricStats(metricValues(slice, 'mem')),
    disk: computeMetricStats(metricValues(slice, 'disk')),
    online: computeMetricStats(metricValues(slice, 'online')),
  }
}

export function parseAlertThresholds(items: SettingItem[]): FleetAlertThresholds {
  const map = new Map(items.map((i) => [i.key, i.value]))
  const num = (k: string, fallback: number) => {
    const v = Number(map.get(k))
    return Number.isFinite(v) && v > 0 ? v : fallback
  }
  return {
    cpu: num('cpu_alert_threshold', 80),
    mem: num('mem_alert_threshold', 80),
    disk: num('disk_alert_threshold', 80),
  }
}

export function formatPointTimeBeijing(recordedAt: string): string {
  const d = parseApiDateTime(recordedAt)
  if (!d) return recordedAt
  return formatDateTimeBeijing(d.toISOString())
}

export function formatDelta(delta: number | null, unit = '%'): string {
  if (delta == null) return '—'
  if (delta === 0) return `0${unit}`
  const sign = delta > 0 ? '+' : ''
  return `${sign}${delta}${unit}`
}

export function pointTimestampMs(recordedAt: string): number | null {
  const d = parseApiDateTime(recordedAt)
  return d ? d.getTime() : null
}

export function findNearestPointIndex(points: FleetTrendPoint[], ts: number): number {
  if (!points.length) return -1
  let best = 0
  let bestDiff = Infinity
  points.forEach((p, i) => {
    const ms = pointTimestampMs(p.recorded_at)
    if (ms == null) return
    const diff = Math.abs(ms - ts)
    if (diff < bestDiff) {
      bestDiff = diff
      best = i
    }
  })
  const spanMs = 10 * 60 * 1000
  return bestDiff <= spanMs / 2 + 1000 ? best : -1
}

export function indexRangeFromZoom(
  pointCount: number,
  startPercent: number,
  endPercent: number,
): { startIdx: number; endIdx: number } {
  if (pointCount <= 0) return { startIdx: 0, endIdx: 0 }
  const startIdx = Math.max(0, Math.floor((startPercent / 100) * (pointCount - 1)))
  const endIdx = Math.min(pointCount - 1, Math.ceil((endPercent / 100) * (pointCount - 1)))
  return { startIdx, endIdx }
}
