/**
 * The operational impact engine (§54, §55, §56, §57).
 *
 * The temptation in a product like this is to put "SAR 2.1 M saved" on the executive
 * dashboard. It is the number people remember and the number that is least defensible:
 * it depends on a tariff, an outage duration, a customer mix and a counterfactual that
 * never happened, and every one of those is an assumption dressed as a measurement.
 *
 * So this module does three things:
 *
 *   1. **Keeps the categories apart.** Technical, operational, customer and financial
 *      impact are computed separately and never summed into one headline (§56). They are
 *      different kinds of claim with different evidence behind them.
 *
 *   2. **Labels every figure.** Each carries an `evidenceKind` — simulated, projected or
 *      observed — that travels with it to the UI. A projected saving and a measured one
 *      look different on screen because they are different (§55, §122).
 *
 *   3. **Publishes its assumptions.** The financial estimate returns the tariff and
 *      duration it used. A number whose assumptions are hidden cannot be argued with, and
 *      one that cannot be argued with should not be shown.
 */

import { clamp, round } from './rng'

export type EvidenceKind = 'simulated' | 'projected' | 'observed'

export interface ImpactFigure {
  key: string
  label: string
  labelAr: string
  value: number
  unit: string
  unitAr: string
  evidenceKind: EvidenceKind
  /** 0–100. How much the figure should be leaned on. */
  confidence: number
  /** low | medium | high — the plain-language version of `confidence` (§55). */
  confidenceBand: 'low' | 'medium' | 'high'
  detail: string
  detailAr: string
}

export interface ImpactAssumption {
  key: string
  label: string
  labelAr: string
  value: string
}

export interface ImpactAssessment {
  technical: ImpactFigure[]
  operational: ImpactFigure[]
  customer: ImpactFigure[]
  financial: ImpactFigure[]
  maintenance: ImpactFigure[]
  assumptions: ImpactAssumption[]
  /** The transparent composite (§57). Never money. */
  impactScore: number
  impactComponents: Array<{ key: string; label: string; labelAr: string; value: number; weight: number }>
}

// ─────────────────────────────────────────────────────────────────────────────
// Assumptions, stated once
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Demo tariff for unserved energy, in SAR per MWh.
 *
 * Deliberately a round, obviously-illustrative figure rather than a precise-looking one:
 * a value like 847.30 would imply a source this build does not have.
 */
const UNSERVED_ENERGY_SAR_PER_MWH = 900

/** Assumed duration of an unmitigated event, in hours, when nothing better is known. */
const DEFAULT_EVENT_HOURS = 2

function band(confidence: number): ImpactFigure['confidenceBand'] {
  if (confidence >= 72) return 'high'
  if (confidence >= 45) return 'medium'
  return 'low'
}

export interface ImpactInput {
  /** Risk with and without the intervention, 0–100. */
  riskBefore: number
  riskAfter: number
  /** Customers behind the origin asset and everything downstream of it. */
  customersAtRisk: number
  /** Load that would not have been served, MW. */
  unservedMw: number
  /** Assets the cascade would have touched. */
  assetsAffected: number
  /** Minutes of warning the platform produced ahead of a conventional threshold. */
  leadMinutes: number | null
  /** Loading before and after, for the asset-stress figure. */
  loadPctBefore: number
  loadPctAfter: number
  tempCBefore: number
  tempCAfter: number
  /** Remaining useful life, days, before and after the intervention. */
  rulDaysBefore: number
  rulDaysAfter: number
  /** How long the intervention takes to execute, minutes. */
  executionMinutes: number
  /** Confidence carried down from the prediction and twin. */
  predictionConfidence: number
  twinFidelity: number
  /** Whether any of this was observed rather than simulated. */
  evidenceKind: EvidenceKind
  eventHours?: number
}

/**
 * Compute the four impact families.
 *
 * Confidence propagates rather than being asserted: an impact figure derived from a
 * prediction cannot be more trustworthy than the prediction, and a financial figure
 * derived from that is less trustworthy again, because it adds a tariff assumption on top.
 */
export function assessImpact(input: ImpactInput): ImpactAssessment {
  const eventHours = input.eventHours ?? DEFAULT_EVENT_HOURS
  const riskDrop = Math.max(0, input.riskBefore - input.riskAfter)

  // The share of the exposure the intervention actually removes. A strategy that takes
  // risk from 90 to 45 removes half of it, not all of it, and the impact figures should
  // be scaled accordingly rather than claiming the whole event was averted.
  const avoidedShare = input.riskBefore > 0 ? clamp(riskDrop / input.riskBefore, 0, 1) : 0

  const baseConfidence = round(
    clamp(Math.min(input.predictionConfidence, input.twinFidelity + 8), 0, 100),
    1,
  )
  const projectedConfidence = round(clamp(baseConfidence * 0.85, 0, 100), 1)
  const financialConfidence = round(clamp(baseConfidence * 0.55, 0, 100), 1)

  const kind = input.evidenceKind

  const figure = (
    key: string,
    label: string,
    labelAr: string,
    value: number,
    unit: string,
    unitAr: string,
    confidence: number,
    detail: string,
    detailAr: string,
    evidenceKind: EvidenceKind = kind,
  ): ImpactFigure => ({
    key,
    label,
    labelAr,
    value: round(value, 2),
    unit,
    unitAr,
    evidenceKind,
    confidence: round(confidence, 1),
    confidenceBand: band(confidence),
    detail,
    detailAr,
  })

  // ── Technical ─────────────────────────────────────────────────────────────
  const technical: ImpactFigure[] = [
    figure(
      'risk_reduction',
      'Risk reduction',
      'خفض الخطر',
      riskDrop,
      'points',
      'نقطة',
      baseConfidence,
      `${round(input.riskBefore, 1)} % → ${round(input.riskAfter, 1)} %`,
      `${round(input.riskBefore, 1)}٪ ← ${round(input.riskAfter, 1)}٪`,
    ),
    figure(
      'loading_relief',
      'Loading relief',
      'تخفيف التحميل',
      Math.max(0, input.loadPctBefore - input.loadPctAfter),
      'points',
      'نقطة',
      baseConfidence,
      `${round(input.loadPctBefore, 1)} % → ${round(input.loadPctAfter, 1)} %`,
      `${round(input.loadPctBefore, 1)}٪ ← ${round(input.loadPctAfter, 1)}٪`,
    ),
    figure(
      'thermal_relief',
      'Thermal relief',
      'تخفيف حراري',
      Math.max(0, input.tempCBefore - input.tempCAfter),
      '°C',
      '°م',
      baseConfidence,
      `${round(input.tempCBefore, 1)} °C → ${round(input.tempCAfter, 1)} °C`,
      `${round(input.tempCBefore, 1)}° ← ${round(input.tempCAfter, 1)}°`,
    ),
    figure(
      'capacity_protected',
      'Capacity protected',
      'القدرة المحمية',
      input.unservedMw * avoidedShare,
      'MW',
      'م.و',
      projectedConfidence,
      `${round(avoidedShare * 100, 0)} % of the exposure removed`,
      `إزالة ${round(avoidedShare * 100, 0)}٪ من التعرض`,
      'projected',
    ),
  ]

  // ── Operational ───────────────────────────────────────────────────────────
  const operational: ImpactFigure[] = [
    figure(
      'assets_protected',
      'Assets kept out of the chain',
      'أصول خارج السلسلة',
      Math.max(0, input.assetsAffected - 1) * avoidedShare,
      'assets',
      'أصل',
      projectedConfidence,
      `${input.assetsAffected} in the modelled cascade`,
      `${input.assetsAffected} في التسلسل المنمذج`,
      'projected',
    ),
    figure(
      'execution_time',
      'Execution time',
      'زمن التنفيذ',
      input.executionMinutes,
      'min',
      'دقيقة',
      92,
      'From approval to full effect',
      'من الاعتماد إلى الأثر الكامل',
      'simulated',
    ),
  ]
  if (input.leadMinutes !== null) {
    operational.push(
      figure(
        'lead_time',
        'Warning ahead of a conventional threshold',
        'إنذار سابق للعتبة التقليدية',
        input.leadMinutes,
        'min',
        'دقيقة',
        baseConfidence,
        'Time between the weak-signal detection and the threshold alarm',
        'الزمن بين كشف الإشارة الضعيفة وإنذار العتبة',
        kind === 'observed' ? 'observed' : 'simulated',
      ),
    )
  }

  // ── Customer ──────────────────────────────────────────────────────────────
  const customersProtected = input.customersAtRisk * avoidedShare
  const customer: ImpactFigure[] = [
    figure(
      'customers_protected',
      'Customers kept on supply',
      'مشتركون على التغذية',
      customersProtected,
      'customers',
      'مشترك',
      projectedConfidence,
      `${input.customersAtRisk.toLocaleString('en')} downstream of the origin`,
      `${input.customersAtRisk.toLocaleString('en')} خلف المصدر`,
      'projected',
    ),
    figure(
      'downtime_avoided',
      'Downtime avoided',
      'انقطاع تم تفاديه',
      eventHours * avoidedShare,
      'hours',
      'ساعة',
      projectedConfidence,
      `Assuming a ${eventHours}-hour unmitigated event`,
      `بافتراض حدث غير معالج مدته ${eventHours} ساعات`,
      'projected',
    ),
  ]

  // ── Financial ─────────────────────────────────────────────────────────────
  // One figure only, at the lowest confidence in the set, with its assumptions attached.
  const energyAvoidedMwh = input.unservedMw * avoidedShare * eventHours
  const financial: ImpactFigure[] = [
    figure(
      'unserved_energy_value',
      'Value of unserved energy avoided',
      'قيمة الطاقة غير المخدومة المتفاداة',
      energyAvoidedMwh * UNSERVED_ENERGY_SAR_PER_MWH,
      'SAR',
      'ريال',
      financialConfidence,
      `${round(energyAvoidedMwh, 1)} MWh at a demonstration tariff of ${UNSERVED_ENERGY_SAR_PER_MWH} SAR/MWh`,
      `${round(energyAvoidedMwh, 1)} م.و.س بتعرفة عرض ${UNSERVED_ENERGY_SAR_PER_MWH} ريال/م.و.س`,
      'projected',
    ),
  ]

  // ── Maintenance ───────────────────────────────────────────────────────────
  const maintenance: ImpactFigure[] = [
    figure(
      'life_extension',
      'Remaining-life change',
      'تغير العمر المتبقي',
      input.rulDaysAfter - input.rulDaysBefore,
      'days',
      'يوم',
      round(baseConfidence * 0.7, 1),
      `${round(input.rulDaysBefore, 0)} → ${round(input.rulDaysAfter, 0)} days`,
      `${round(input.rulDaysBefore, 0)} ← ${round(input.rulDaysAfter, 0)} يومًا`,
      'projected',
    ),
  ]

  // ── The composite (§57) ───────────────────────────────────────────────────
  // Transparent by construction: five named components, published weights, and every
  // input already visible above. Not money, and not a percentage of anything.
  const components = [
    {
      key: 'risk_reduction',
      label: 'Risk reduction',
      labelAr: 'خفض الخطر',
      value: round(clamp(riskDrop / 60, 0, 1) * 100, 1),
      weight: 0.3,
    },
    {
      key: 'capacity_protected',
      label: 'Capacity protected',
      labelAr: 'القدرة المحمية',
      value: round(clamp((input.unservedMw * avoidedShare) / 40, 0, 1) * 100, 1),
      weight: 0.2,
    },
    {
      key: 'downtime_avoided',
      label: 'Downtime avoided',
      labelAr: 'انقطاع متفادى',
      value: round(clamp((eventHours * avoidedShare) / 4, 0, 1) * 100, 1),
      weight: 0.2,
    },
    {
      key: 'asset_stress',
      label: 'Asset stress reduced',
      labelAr: 'خفض إجهاد الأصل',
      value: round(clamp(Math.max(0, input.tempCBefore - input.tempCAfter) / 12, 0, 1) * 100, 1),
      weight: 0.15,
    },
    {
      key: 'recovery',
      label: 'Speed of response',
      labelAr: 'سرعة الاستجابة',
      value: round(clamp(1 - input.executionMinutes / 90, 0, 1) * 100, 1),
      weight: 0.15,
    },
  ]

  const impactScore = round(
    clamp(
      components.reduce((sum, c) => sum + c.value * c.weight, 0),
      0,
      100,
    ),
    1,
  )

  return {
    technical,
    operational,
    customer,
    financial,
    maintenance,
    assumptions: [
      {
        key: 'tariff',
        label: 'Unserved-energy tariff',
        labelAr: 'تعرفة الطاقة غير المخدومة',
        value: `${UNSERVED_ENERGY_SAR_PER_MWH} SAR/MWh (demonstration figure)`,
      },
      {
        key: 'duration',
        label: 'Assumed unmitigated event duration',
        labelAr: 'مدة الحدث غير المعالج المفترضة',
        value: `${eventHours} hours`,
      },
      {
        key: 'avoided_share',
        label: 'Share of exposure removed',
        labelAr: 'حصة التعرض المزالة',
        value: `${round(avoidedShare * 100, 1)} % (from the risk change)`,
      },
      {
        key: 'evidence',
        label: 'Evidence basis',
        labelAr: 'أساس الدليل',
        value: kind,
      },
    ],
    impactScore,
    impactComponents: components,
  }
}
