import 'server-only'

import { getGridSnapshot } from './grid-service'
import { getHubOverview } from './integration-service'
import { riskToState, type GridState } from '../domain/enums'
import { round } from '../engine/rng'

/**
 * The compact payload pushed over the live stream.
 *
 * Deliberately small. A full snapshot carries 250 assets with their risk breakdowns; at
 * a three-second cadence that would be megabytes per minute per viewer for data no
 * dashboard tile actually reads. The stream carries the headline figures and the few
 * rows that change visibly; anything deeper is fetched on demand (§50).
 */
export interface LiveRegion {
  code: string
  loadMw: number
  peakRisk: number
  state: GridState
  tempC: number
  renewableMw: number
}

export interface LiveAsset {
  code: string
  name: string
  nameAr: string
  regionCode: string
  risk: number
  state: GridState
  loadPct: number
  tempC: number
  dnaSimilarity: number
}

export interface LiveSnapshot {
  ts: number
  totalLoadMw: number
  totalCapacityMw: number
  availableCapacityMw: number
  reserveMarginPct: number
  renewableMw: number
  renewableSharePct: number
  solarMw: number
  windMw: number
  batteryMw: number
  frequencyHz: number
  stabilityIndex: number
  averageHealth: number
  loadRatio: number
  state: GridState
  criticalCount: number
  warningCount: number
  regions: LiveRegion[]
  topAssets: LiveAsset[]
  /**
   * The state of the platform's inputs, carried on the same tick as its outputs.
   *
   * A live figure whose source has stopped delivering is not a live figure, and putting
   * the two on separate screens lets a stale reading keep its authority. `weakestSource`
   * names the connector dragging the mean down so the fix has an address (4.1).
   */
  integrations: {
    sources: number
    connected: number
    degraded: number
    disconnected: number
    meanQuality: number
    throughputPerMin: number
    weakestSource: { code: string; label: string; quality: number } | null
  }
}

export async function buildLiveSnapshot(ts = Date.now()): Promise<LiveSnapshot> {
  const [snapshot, hub] = await Promise.all([getGridSnapshot({ ts }), getHubOverview()])

  const weakest = [...hub.connectors].sort((a, b) => a.dataQuality - b.dataQuality)[0] ?? null

  return {
    ts: snapshot.ts,
    totalLoadMw: snapshot.totalLoadMw,
    totalCapacityMw: snapshot.totalCapacityMw,
    availableCapacityMw: snapshot.availableCapacityMw,
    reserveMarginPct: snapshot.reserveMarginPct,
    renewableMw: snapshot.renewableMw,
    renewableSharePct: snapshot.renewableSharePct,
    solarMw: snapshot.solarMw,
    windMw: snapshot.windMw,
    batteryMw: snapshot.batteryMw,
    frequencyHz: snapshot.frequencyHz,
    stabilityIndex: snapshot.stabilityIndex,
    averageHealth: snapshot.averageHealth,
    loadRatio: snapshot.loadRatio,
    state: snapshot.state,
    criticalCount: snapshot.assets.filter((asset) => asset.risk.score >= 75).length,
    warningCount: snapshot.assets.filter(
      (asset) => asset.risk.score >= 55 && asset.risk.score < 75,
    ).length,
    integrations: {
      sources: hub.total,
      connected: hub.connected,
      degraded: hub.degraded,
      disconnected: hub.disconnected + hub.error,
      meanQuality: hub.meanQuality,
      throughputPerMin: hub.throughputPerMin,
      weakestSource: weakest
        ? { code: weakest.code, label: weakest.label, quality: weakest.dataQuality }
        : null,
    },
    regions: snapshot.regions.map((region) => ({
      code: region.code,
      loadMw: region.loadMw,
      peakRisk: region.peakRisk,
      state: region.state,
      tempC: round(region.env.tempC, 1),
      renewableMw: region.renewableMw,
    })),
    topAssets: snapshot.assets
      .slice()
      .sort((a, b) => b.risk.score - a.risk.score)
      .slice(0, 8)
      .map((asset) => ({
        code: asset.profile.code,
        name: asset.profile.code,
        nameAr: asset.profile.code,
        regionCode: asset.profile.regionCode,
        risk: asset.risk.score,
        state: riskToState(asset.risk.score),
        loadPct: asset.sample.loadPct,
        tempC: asset.sample.tempC,
        dnaSimilarity: asset.dnaSimilarity,
      })),
  }
}
