/**
 * The shapes the Live 3D Grid's client components pass between themselves (4.2).
 *
 * Deliberately narrower than the service's payload. The renderer needs geometry and a
 * handful of readings; giving it the whole `LiveGridPayload` would let a scene component
 * reach for a field the 2D fallback does not have, and the two views would drift.
 */

/** The thirteen electrical layers (§13). */
export const GRID_LAYERS = [
  'power_flow',
  'voltage',
  'current',
  'load',
  'frequency',
  'temperature',
  'health',
  'risk',
  'failure_dna',
  'cascade',
  'predicted',
  'maintenance',
  'data_quality',
  'xray',
] as const

export type GridLayer = (typeof GRID_LAYERS)[number]

export interface SceneNode {
  code: string
  name: string
  nameAr: string
  assetTypeKey: string
  shape: string
  x: number
  y: number
  z: number
  scale: number
  rotationY: number
  capacityMw: number
  customersServed: number
  isFocus: boolean
}

export interface SceneEdge {
  from: string
  to: string
  kind: string
  /** The end power is leaving, after the solve. Equals `from` unless the flow reversed. */
  sourceCode: string
  sinkCode: string
  direction: 'forward' | 'reverse' | 'idle'
  activePowerMw: number
  currentA: number
  utilisationPct: number
  /** 0–1, from active power. Drives line emphasis and particle speed. */
  intensity: number
  state: string
}

export interface SceneAsset {
  code: string
  name: string
  nameAr: string
  assetTypeKey: string
  loadPct: number
  loadMw: number
  capacityMw: number
  activePowerMw: number
  reactivePowerMvar: number
  voltageKv: number
  voltageDeviationPct: number
  currentA: number
  /** Nameplate current, so the current layer has a denominator rather than a guess. */
  ratedCurrentA: number
  powerFactor: number
  frequencyHz: number
  tempC: number
  ambientC: number
  thermalStress: number
  healthScore: number
  riskScore: number
  state: string
  isOutage: boolean
  socPct: number | null
  role: string
  customersServed: number
  rulDays: number
  /** Fields the risk, DNA, cascade, maintenance and quality layers read. */
  dnaMatchPct: number
  cascadeDepth: number | null
  predictedRisk: number | null
  hasOpenWorkOrder: boolean
  dataQualityPct: number
  /** Where these numbers came from. Never inferred by a component. */
  kind: string
}

export interface GridKpis {
  stabilityIndex: number
  totalLoadMw: number
  availableCapacityMw: number
  renewableMw: number
  renewableSharePct: number
  frequencyHz: number
  totalActivePowerMw: number
  totalReactivePowerMvar: number
  assetsAtRisk: number
  criticalAlerts: number
  dataConfidencePct: number
  ambientC: number
  peakRisk: number
}

export interface ConnectionBanner {
  dataSource: 'live' | 'demo' | 'none'
  status: 'connected' | 'degraded' | 'disconnected'
  lastUpdateTs: number | null
  latencyMs: number
  dataQualityPct: number
  sources: number
  sourcesDelivering: number
  weakestSource: { code: string; label: string; quality: number } | null
}

export interface SceneAlert {
  code: string
  assetCode: string
  level: string
  title: string
  titleAr: string
  status: string
  riskScore: number
  raisedAt: number
  expectedAt: number | null
}

/** The connection state of the browser's own stream, distinct from the sources' (§107). */
export type StreamState =
  | 'connecting'
  | 'connected'
  | 'reconnecting'
  | 'disconnected'
  | 'offline'
  | 'stale'
