import 'server-only'

import { REGIONS } from '../data/regions'
import { sampleEnvironment, solarCapacityFactor, windCapacityFactor } from '../engine/environment'
import {
  forecastLoad,
  forecastRenewable,
  renewableConfidenceScore,
  type ForecastPoint,
} from '../engine/forecast'
import { round } from '../engine/rng'
import { loadAssetProfiles } from './grid-service'

export interface LoadForecastView {
  points: ForecastPoint[]
  peak: ForecastPoint
  capacityMw: number
  minReserveMarginPct: number
  currentMw: number
  horizonMin: number
  regional: Array<{
    code: string
    name: string
    nameAr: string
    peakMw: number
    peakAt: number
    capacityMw: number
    reserveMarginPct: number
    currentMw: number
  }>
}

/**
 * Load forecast (§17).
 *
 * Computed live rather than read from `load_forecasts`. The stored rows are the forecast
 * as it stood when it was issued — useful for measuring forecast error later — but an
 * operator asking "what does the next 24 hours look like" wants the current answer.
 */
export async function getLoadForecast(
  horizonMin = 1440,
  regionCode?: string | null,
): Promise<LoadForecastView> {
  const profiles = await loadAssetProfiles()
  const now = Date.now()
  const stepMin = horizonMin > 1440 ? 180 : horizonMin > 360 ? 60 : 15

  const national = forecastLoad(profiles, now, { horizonMin, stepMin, regionCode })

  const regional = REGIONS.map((region) => {
    const forecast = forecastLoad(profiles, now, {
      horizonMin,
      stepMin: Math.max(stepMin, 60),
      regionCode: region.code,
    })
    return {
      code: region.code,
      name: region.name,
      nameAr: region.nameAr,
      peakMw: forecast.peak.expectedMw,
      peakAt: forecast.peak.ts,
      capacityMw: forecast.capacityMw,
      reserveMarginPct: forecast.minReserveMarginPct,
      currentMw: forecast.points[0]?.expectedMw ?? 0,
    }
  }).sort((a, b) => b.peakMw - a.peakMw)

  return {
    ...national,
    currentMw: national.points[0]?.expectedMw ?? 0,
    regional,
  }
}

export interface RenewableView {
  kind: 'solar' | 'wind'
  points: ForecastPoint[]
  peak: ForecastPoint
  capacityMw: number
  currentMw: number
  variabilityMw: number
  confidence: number
  capacityFactor: number
}

export interface RenewableIntelligence {
  solar: RenewableView
  wind: RenewableView
  confidenceScore: number
  totalCurrentMw: number
  totalCapacityMw: number
  conditions: Array<{
    code: string
    name: string
    nameAr: string
    tempC: number
    irradianceWm2: number
    windSpeedMs: number
    dustIndex: number
    cloudCoverPct: number
    solarCapacityFactor: number
    windCapacityFactor: number
  }>
}

/** Renewable intelligence (§18): output, forecast, variability and confidence. */
export async function getRenewableIntelligence(horizonMin = 1440): Promise<RenewableIntelligence> {
  const profiles = await loadAssetProfiles()
  const now = Date.now()
  const stepMin = horizonMin > 720 ? 60 : 30

  const solar = forecastRenewable(profiles, now, 'solar', { horizonMin, stepMin })
  const wind = forecastRenewable(profiles, now, 'wind', { horizonMin, stepMin })

  const view = (forecast: typeof solar): RenewableView => ({
    kind: forecast.kind,
    points: forecast.points,
    peak: forecast.peak,
    capacityMw: forecast.capacityMw,
    currentMw: forecast.points[0]?.expectedMw ?? 0,
    variabilityMw: forecast.variabilityMw,
    confidence: forecast.points[Math.min(6, forecast.points.length - 1)]?.confidence ?? 0,
    capacityFactor: round(
      forecast.capacityMw > 0 ? ((forecast.points[0]?.expectedMw ?? 0) / forecast.capacityMw) * 100 : 0,
      1,
    ),
  })

  const conditions = REGIONS.map((region) => {
    const env = sampleEnvironment(region, now)
    return {
      code: region.code,
      name: region.name,
      nameAr: region.nameAr,
      tempC: round(env.tempC, 1),
      irradianceWm2: round(env.irradianceWm2, 0),
      windSpeedMs: round(env.windSpeedMs, 1),
      dustIndex: round(env.dustIndex, 2),
      cloudCoverPct: round(env.cloudCoverPct, 0),
      solarCapacityFactor: round(solarCapacityFactor(env) * 100, 1),
      windCapacityFactor: round(windCapacityFactor(env) * 100, 1),
    }
  })

  return {
    solar: view(solar),
    wind: view(wind),
    confidenceScore: renewableConfidenceScore(solar, wind),
    totalCurrentMw: round((solar.points[0]?.expectedMw ?? 0) + (wind.points[0]?.expectedMw ?? 0), 1),
    totalCapacityMw: round(solar.capacityMw + wind.capacityMw, 1),
    conditions,
  }
}
