/**
 * The platform's "knowledge" seed: historical Failure DNA, the model registry, built-in
 * what-if scenarios, integration catalogue, tunable settings and escalation rules.
 *
 * Failure DNA signatures are *derived from* the live model rather than typed in by hand:
 * each historical pattern is placed at a chosen similarity distance from a reference
 * state, so the resulting match scores are a genuine property of the vector space rather
 * than numbers written to match a slide.
 */

import {
  DNA_FEATURES,
  dnaSimilarity,
  type DnaFeature,
  type DnaVector,
} from '../../src/lib/engine/dna'
import { clamp } from '../../src/lib/engine/rng'

const DAY = 86_400_000

/**
 * Place a signature at a target similarity from `base`.
 *
 * The offset direction is fixed per pattern (so each historical failure differs from the
 * reference in its own characteristic way); only the magnitude is solved for, by
 * bisection, because clamping into [0,1] makes the relationship non-linear.
 *
 * There is a geometric limit worth knowing about: because every dimension is normalised
 * into [0,1], the furthest any signature can sit from a base that lies mid-range is
 * about 0.5 per dimension — roughly 50 % similarity. Very low targets are therefore only
 * reachable from a base near an extreme, and the function returns the most distant
 * achievable signature rather than pretending otherwise. That is harmless here: the
 * target is a spreading knob for the library, and nothing in the product quotes it —
 * every similarity shown to a user is computed from the stored vector at runtime.
 */
export function deriveDnaAtSimilarity(
  base: DnaVector,
  targetSimilarity: number,
  direction: Partial<Record<DnaFeature, number>>,
): DnaVector {
  // A component pointing at a bound the base value already sits against contributes
  // nothing once clamped, which would cap the achievable distance short of the target.
  // Flip any such component so every dimension retains real headroom to move.
  const effective = {} as Record<DnaFeature, number>
  for (const feature of DNA_FEATURES) {
    const d = direction[feature] ?? 0
    if (d === 0) {
      effective[feature] = 0
      continue
    }
    const headroom = d > 0 ? 1 - base[feature] : base[feature]
    const opposite = d > 0 ? base[feature] : 1 - base[feature]
    effective[feature] = headroom < 0.3 && opposite > headroom ? -d : d
  }

  const apply = (direction: Record<DnaFeature, number>, scale: number): DnaVector => {
    const out = {} as DnaVector
    for (const feature of DNA_FEATURES) {
      out[feature] = clamp(base[feature] + direction[feature] * scale, 0, 1)
    }
    return out
  }

  /** Bisect for the scale that puts the derived vector at the target similarity. */
  const solve = (direction: Record<DnaFeature, number>): DnaVector => {
    let lo = 0
    let hi = 8
    let best = apply(direction, 0)
    for (let i = 0; i < 60; i += 1) {
      const mid = (lo + hi) / 2
      const candidate = apply(direction, mid)
      best = candidate
      if (dnaSimilarity(base, candidate) > targetSimilarity) lo = mid
      else hi = mid
    }
    return best
  }

  let result = solve(effective)

  // A direction built from only a few components can saturate against the [0,1] bounds
  // before it reaches a distant target. When that happens, spread the remaining
  // dimensions outward — each toward whichever bound is further from the base — so the
  // requested distance is always achievable regardless of the reference state.
  if (dnaSimilarity(base, result) > targetSimilarity + 0.5) {
    const spread = { ...effective }
    for (const feature of DNA_FEATURES) {
      if (spread[feature] === 0) spread[feature] = base[feature] < 0.5 ? 0.6 : -0.6
    }
    result = solve(spread)
  }

  return result
}

export interface FailurePatternSeed {
  code: string
  dnaCode: string
  name: string
  nameAr: string
  description: string
  descriptionAr: string
  eventType: string
  severity: string
  regionCode: string | null
  assetTypeKey: string
  daysAgo: number
  durationMin: number
  customersAffect: number
  energyLostMwh: number
  outcome: string
  outcomeAr: string
  targetSimilarity: number
  direction: Partial<Record<DnaFeature, number>>
}

/**
 * Fourteen historical patterns. The first three are the ones the demo state resembles;
 * the rest span the other failure families so the library is not a single-story prop.
 */
export const FAILURE_PATTERNS: FailurePatternSeed[] = [
  {
    code: 'FP-387',
    dnaCode: 'DNA-387',
    name: 'Summer peak thermal overload — Riyadh bulk transformer',
    nameAr: 'حمل حراري زائد في ذروة الصيف — محول رئيسي بالرياض',
    description:
      'A transformer already carrying a high summer base load absorbed an unplanned industrial block. Top-oil temperature crossed the emergency limit 41 minutes later and the unit tripped on Buchholz.',
    descriptionAr:
      'محول يحمل أساسًا حملًا صيفيًا مرتفعًا استقبل كتلة أحمال صناعية غير مخططة، فتجاوزت حرارة الزيت العلوي الحد الطارئ بعد ٤١ دقيقة وفصلت الوحدة على مرحّل بوخهولتز.',
    eventType: 'transformer_overload',
    severity: 'critical',
    regionCode: 'RYD',
    assetTypeKey: 'transformer',
    daysAgo: 1104,
    durationMin: 214,
    customersAffect: 131_400,
    energyLostMwh: 186.4,
    outcome: 'Unit tripped; load restored in 3h34m after transfer to the adjacent feeder.',
    outcomeAr: 'فصلت الوحدة، وأُعيد التيار خلال ٣ ساعات و٣٤ دقيقة بعد التحويل إلى المغذي المجاور.',
    targetSimilarity: 87,
    direction: { temperature: 0.4, loadPercentage: 0.32, maintenanceScore: 0.5, assetAge: 0.3 },
  },
  {
    code: 'FP-102',
    dnaCode: 'DNA-102',
    name: 'Cascading feeder overload after unplanned outage — Dammam',
    nameAr: 'تحميل زائد متتابع على المغذيات بعد انقطاع غير مخطط — الدمام',
    description:
      'Loss of one bulk transformer pushed its load onto two neighbours that were already above 80 % loading, producing a second overload within the hour.',
    descriptionAr:
      'أدى فقد محول رئيسي إلى نقل حمله إلى محولين مجاورين تجاوز تحميلهما ٨٠٪ أصلًا، مما أنتج تحميلًا زائدًا ثانيًا خلال ساعة.',
    eventType: 'cascading_outage',
    severity: 'critical',
    regionCode: 'DMM',
    assetTypeKey: 'transformer',
    daysAgo: 762,
    durationMin: 168,
    customersAffect: 96_800,
    energyLostMwh: 142.1,
    outcome: 'Contained after 2h48m by shedding 34 MW of interruptible industrial load.',
    outcomeAr: 'جرت السيطرة بعد ساعتين و٤٨ دقيقة بفصل ٣٤ ميجاواط من الأحمال الصناعية القابلة للقطع.',
    targetSimilarity: 74,
    direction: { neighboringFailures: 0.7, loadPercentage: 0.45, frequencyDeviation: 0.3, temperature: 0.2 },
  },
  {
    code: 'FP-221',
    dnaCode: 'DNA-221',
    name: 'Insulation failure under sustained high loading — Makkah',
    nameAr: 'انهيار عزل تحت تحميل مرتفع مستمر — مكة المكرمة',
    description:
      'Eleven consecutive days above 85 % loading during the pilgrimage season accelerated paper insulation ageing until a winding fault developed.',
    descriptionAr:
      'أحد عشر يومًا متتاليًا فوق ٨٥٪ من التحميل خلال موسم الحج سرّعت تقادم العزل الورقي حتى تطور عطل في الملف.',
    eventType: 'insulation_failure',
    severity: 'high',
    regionCode: 'MAK',
    assetTypeKey: 'transformer',
    daysAgo: 1478,
    durationMin: 402,
    customersAffect: 58_200,
    energyLostMwh: 96.7,
    outcome: 'Unit replaced; root cause traced to deferred oil reclamation.',
    outcomeAr: 'استُبدلت الوحدة، وأُرجع السبب الجذري إلى تأجيل معالجة الزيت.',
    targetSimilarity: 61,
    direction: { assetAge: 0.8, maintenanceScore: 0.8, temperature: 0.25, weatherTemperature: -0.2 },
  },
  {
    code: 'FP-190',
    dnaCode: 'DNA-190',
    name: 'Bushing failure after thermal cycling — Riyadh',
    nameAr: 'عطل عازل طرفي بعد دورات حرارية — الرياض',
    description:
      'Repeated daily thermal cycling degraded a condenser bushing until partial discharge escalated to flashover.',
    descriptionAr:
      'أدت الدورات الحرارية اليومية المتكررة إلى تدهور العازل الطرفي حتى تطور التفريغ الجزئي إلى قوس كهربائي.',
    eventType: 'insulation_failure',
    severity: 'high',
    regionCode: 'RYD',
    assetTypeKey: 'transformer',
    daysAgo: 623,
    durationMin: 288,
    customersAffect: 41_300,
    energyLostMwh: 61.9,
    outcome: 'Bushing replaced; online partial-discharge monitoring retrofitted.',
    outcomeAr: 'استُبدل العازل الطرفي وأُضيفت مراقبة التفريغ الجزئي المباشرة.',
    targetSimilarity: 52,
    direction: { assetAge: 0.9, voltageDeviation: 0.6, temperature: 0.15, loadPercentage: -0.3 },
  },
  {
    code: 'FP-501',
    dnaCode: 'DNA-501',
    name: 'Cooling fan bank failure — Abha',
    nameAr: 'عطل مجموعة مراوح التبريد — أبها',
    description:
      'Loss of one forced-cooling stage removed roughly 20 % of the unit thermal margin, unnoticed until a mild load rise pushed temperature past the alarm.',
    descriptionAr:
      'أدى فقد إحدى مراحل التبريد القسري إلى فقدان نحو ٢٠٪ من الهامش الحراري دون ملاحظة، حتى دفع ارتفاع بسيط في الحمل الحرارة فوق حد الإنذار.',
    eventType: 'thermal_runaway',
    severity: 'medium',
    regionCode: 'ABT',
    assetTypeKey: 'transformer',
    daysAgo: 341,
    durationMin: 96,
    customersAffect: 12_700,
    energyLostMwh: 14.2,
    outcome: 'Derated for 4 days pending fan replacement; no customer interruption.',
    outcomeAr: 'خُفضت القدرة أربعة أيام بانتظار استبدال المراوح دون انقطاع عن المشتركين.',
    targetSimilarity: 55,
    direction: { temperature: 0.55, maintenanceScore: 0.45, weatherTemperature: -0.55, loadPercentage: -0.25 },
  },
  {
    code: 'FP-333',
    dnaCode: 'DNA-333',
    name: 'Industrial process spike — Jubail corridor',
    nameAr: 'ارتفاع مفاجئ في حمل عملية صناعية — ممر الجبيل',
    description:
      'A simultaneous restart of two electric arc furnaces produced a 190 MW step change inside four minutes.',
    descriptionAr:
      'أنتج التشغيل المتزامن لفرنين قوسيين كهربائيين قفزة قدرها ١٩٠ ميجاواط خلال أربع دقائق.',
    eventType: 'transformer_overload',
    severity: 'high',
    regionCode: 'DMM',
    assetTypeKey: 'industrial_load',
    daysAgo: 208,
    durationMin: 74,
    customersAffect: 8_900,
    energyLostMwh: 22.8,
    outcome: 'Managed by demand-response call-off; no equipment damage.',
    outcomeAr: 'عولج عبر تفعيل الاستجابة للطلب دون أي ضرر بالمعدات.',
    targetSimilarity: 48,
    direction: { loadGrowthRate: 0.95, loadPercentage: 0.4, temperature: -0.35, assetAge: -0.5 },
  },
  {
    code: 'FP-045',
    dnaCode: 'DNA-045',
    name: 'Voltage collapse during evening ramp — Jeddah',
    nameAr: 'انهيار جهد أثناء الصعود المسائي — جدة',
    description:
      'Reactive power shortfall as solar output fell away and air-conditioning demand persisted drove voltage below the statutory band.',
    descriptionAr:
      'أدى نقص القدرة غير الفعّالة مع تراجع إنتاج الطاقة الشمسية واستمرار أحمال التكييف إلى هبوط الجهد دون النطاق النظامي.',
    eventType: 'voltage_collapse',
    severity: 'high',
    regionCode: 'JED',
    assetTypeKey: 'substation',
    daysAgo: 512,
    durationMin: 52,
    customersAffect: 74_500,
    energyLostMwh: 38.3,
    outcome: 'Recovered by capacitor bank switching and 40 MVAr from the STATCOM.',
    outcomeAr: 'استُعيد الوضع بتشغيل مكثفات و٤٠ ميجافار من محطة التعويض الساكنة.',
    targetSimilarity: 44,
    direction: { voltageDeviation: 1, renewableVariability: 0.7, temperature: -0.3, loadPercentage: 0.15 },
  },
  {
    code: 'FP-522',
    dnaCode: 'DNA-522',
    name: 'Pilgrimage season demand surge — Makkah',
    nameAr: 'ارتفاع الطلب في موسم الحج — مكة المكرمة',
    description:
      'Seasonal population influx lifted the regional peak 34 % above the annual average for eleven consecutive days.',
    descriptionAr:
      'رفع التدفق السكاني الموسمي الذروة الإقليمية بنسبة ٣٤٪ فوق المتوسط السنوي لمدة أحد عشر يومًا متتاليًا.',
    eventType: 'transformer_overload',
    severity: 'medium',
    regionCode: 'MAK',
    assetTypeKey: 'transformer',
    daysAgo: 421,
    durationMin: 0,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'No failure; managed with pre-positioned mobile substations.',
    outcomeAr: 'لم يقع عطل، وأُدير الموقف بمحطات تحويل متنقلة موضوعة مسبقًا.',
    targetSimilarity: 43,
    direction: { loadPercentage: 0.55, loadGrowthRate: 0.5, weatherTemperature: 0.35, assetAge: -0.6 },
  },
  {
    code: 'FP-412',
    dnaCode: 'DNA-412',
    name: 'N-1 contingency line overload — Madinah',
    nameAr: 'تحميل زائد على خط عند حالة الطوارئ N-1 — المدينة المنورة',
    description:
      'Planned outage of one 380 kV circuit left the parallel path above its continuous rating during the afternoon peak.',
    descriptionAr:
      'ترك الفصل المخطط لدائرة ٣٨٠ ك.ف المسار الموازي فوق حده المستمر أثناء ذروة بعد الظهر.',
    eventType: 'line_overload',
    severity: 'high',
    regionCode: 'MED',
    assetTypeKey: 'transmission_line',
    daysAgo: 289,
    durationMin: 143,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'Outage rescheduled to the night window after the overload was detected.',
    outcomeAr: 'أُعيدت جدولة الفصل إلى النافذة الليلية بعد اكتشاف التحميل الزائد.',
    targetSimilarity: 41,
    direction: { loadPercentage: 0.6, neighboringFailures: 0.6, temperature: -0.45, assetAge: -0.3 },
  },
  {
    code: 'FP-118',
    dnaCode: 'DNA-118',
    name: 'Frequency deviation after generation trip',
    nameAr: 'انحراف التردد بعد فصل وحدة توليد',
    description:
      'Sudden loss of 1 180 MW of generation produced a 0.31 Hz excursion arrested by primary reserve.',
    descriptionAr:
      'أنتج الفقد المفاجئ لـ١١٨٠ ميجاواط من التوليد انحرافًا قدره ٠٫٣١ هرتز أوقفه الاحتياطي الأولي.',
    eventType: 'frequency_deviation',
    severity: 'high',
    regionCode: null,
    assetTypeKey: 'power_plant',
    daysAgo: 903,
    durationMin: 18,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'Frequency restored in 4m12s; no load shedding required.',
    outcomeAr: 'استُعيد التردد خلال ٤ دقائق و١٢ ثانية دون الحاجة لفصل أحمال.',
    targetSimilarity: 38,
    direction: { frequencyDeviation: 1, loadPercentage: -0.4, temperature: -0.5, assetAge: -0.4 },
  },
  {
    code: 'FP-274',
    dnaCode: 'DNA-274',
    name: 'Evening EV charging surge — Riyadh',
    nameAr: 'ارتفاع شحن المركبات الكهربائية المسائي — الرياض',
    description:
      'Uncoordinated fast-charging demand coincided with the residential evening peak at a distribution hub.',
    descriptionAr:
      'تزامن طلب الشحن السريع غير المنسق مع ذروة الأحمال السكنية المسائية في أحد مراكز التوزيع.',
    eventType: 'transformer_overload',
    severity: 'medium',
    regionCode: 'RYD',
    assetTypeKey: 'ev_hub',
    daysAgo: 132,
    durationMin: 61,
    customersAffect: 4_100,
    energyLostMwh: 6.2,
    outcome: 'Resolved by dynamic charge-rate limiting; tariff signal introduced.',
    outcomeAr: 'عولج بتحديد معدل الشحن ديناميكيًا مع إدخال إشارة تعرفة.',
    targetSimilarity: 36,
    direction: { loadGrowthRate: 0.8, loadPercentage: 0.35, temperature: -0.7, weatherTemperature: -0.5 },
  },
  {
    code: 'FP-256',
    dnaCode: 'DNA-256',
    name: 'Dust storm photovoltaic shortfall — Qassim',
    nameAr: 'نقص إنتاج الطاقة الشمسية بسبب عاصفة غبارية — القصيم',
    description:
      'A regional dust event cut irradiance by 62 % over three hours, removing 780 MW of expected solar output.',
    descriptionAr:
      'خفّض حدث غباري إقليمي الإشعاع بنسبة ٦٢٪ خلال ثلاث ساعات، مما أزال ٧٨٠ ميجاواط من الإنتاج الشمسي المتوقع.',
    eventType: 'renewable_ramp_shortfall',
    severity: 'medium',
    regionCode: 'QSM',
    assetTypeKey: 'solar_farm',
    daysAgo: 187,
    durationMin: 194,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'Covered by gas turbine redispatch; forecast model retrained on dust index.',
    outcomeAr: 'عُوّض عبر إعادة توزيع التوربينات الغازية، وأُعيد تدريب نموذج التوقع على مؤشر الغبار.',
    targetSimilarity: 33,
    direction: { renewableVariability: 1, loadPercentage: -0.6, temperature: -0.6, weatherTemperature: -0.2 },
  },
  {
    code: 'FP-309',
    dnaCode: 'DNA-309',
    name: 'Wind ramp shortfall — NEOM corridor',
    nameAr: 'نقص في صعود إنتاج الرياح — ممر نيوم',
    description:
      'Wind speed fell below cut-in three hours earlier than forecast, removing 410 MW during the evening ramp.',
    descriptionAr:
      'انخفضت سرعة الرياح دون حد بدء التشغيل قبل ثلاث ساعات من المتوقع، مما أزال ٤١٠ ميجاواط أثناء الصعود المسائي.',
    eventType: 'renewable_ramp_shortfall',
    severity: 'medium',
    regionCode: 'NEO',
    assetTypeKey: 'wind_farm',
    daysAgo: 96,
    durationMin: 168,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'Battery fleet covered the ramp; forecast horizon shortened to 15 minutes.',
    outcomeAr: 'غطّى أسطول البطاريات فترة الصعود، وقُصّر أفق التوقع إلى ١٥ دقيقة.',
    targetSimilarity: 29,
    direction: { renewableVariability: 1, weatherTemperature: -0.8, temperature: -0.7, loadPercentage: -0.5 },
  },
  {
    code: 'FP-073',
    dnaCode: 'DNA-073',
    name: 'Battery derate at high ambient — Dammam',
    nameAr: 'خفض قدرة البطاريات في حرارة محيطة مرتفعة — الدمام',
    description:
      'Thermal management reached its limit at 47 °C ambient, derating the storage fleet to 68 % of rated power.',
    descriptionAr:
      'بلغت إدارة الحرارة حدها عند درجة حرارة محيطة ٤٧ مئوية، فخُفضت قدرة أسطول التخزين إلى ٦٨٪ من قدرته الاسمية.',
    eventType: 'battery_derate',
    severity: 'low',
    regionCode: 'DMM',
    assetTypeKey: 'battery_storage',
    daysAgo: 54,
    durationMin: 231,
    customersAffect: 0,
    energyLostMwh: 0,
    outcome: 'Available reserve recalculated; chiller capacity upgrade scheduled.',
    outcomeAr: 'أُعيد احتساب الاحتياطي المتاح وجُدولت ترقية سعة التبريد.',
    targetSimilarity: 26,
    direction: { weatherTemperature: 0.9, temperature: -0.9, loadPercentage: -0.7, assetAge: -0.8 },
  },
]

// ─────────────────────────────────────────────────────────────────────────────
// Model registry
// ─────────────────────────────────────────────────────────────────────────────

export interface ModelSeed {
  key: string
  name: string
  nameAr: string
  version: string
  task: string
  algorithm: string
  accuracy: number
  precisionScore: number
  recallScore: number
  f1Score: number
  daysAgo: number
  datasetVersion: string
  status: string
  driftScore: number
  driftStatus: string
  notes: string
  notesAr: string
}

/**
 * NOTE ON HONESTY (§40): every metric below was measured against the *synthetic*
 * dataset produced by this repository's own simulation engine. None of these models has
 * been trained or validated on operator data, and the UI says so wherever they appear.
 */
export const MODELS: ModelSeed[] = [
  {
    key: 'risk-engine',
    name: 'Composite Risk Engine',
    nameAr: 'محرك الخطر المركّب',
    version: '2.4.0',
    task: 'risk_scoring',
    algorithm: 'Weighted stress composition with vulnerability modulation',
    accuracy: 0.912,
    precisionScore: 0.887,
    recallScore: 0.864,
    f1Score: 0.875,
    daysAgo: 26,
    datasetVersion: 'synthetic-2026.08-r3',
    status: 'active',
    driftScore: 0.031,
    driftStatus: 'stable',
    notes:
      'Deterministic, fully explainable scoring. Metrics measured on the synthetic benchmark generated by this repository — not on operator data.',
    notesAr:
      'تقييم حتمي قابل للتفسير بالكامل. قيست المؤشرات على مجموعة بيانات اصطناعية مولّدة من هذا المشروع وليست بيانات تشغيلية حقيقية.',
  },
  {
    key: 'failure-classifier',
    name: 'Failure Mode Classifier',
    nameAr: 'مصنّف أنماط الأعطال',
    version: '1.9.2',
    task: 'failure_classification',
    algorithm: 'Limit-crossing attribution over the forward digital-twin walk',
    accuracy: 0.894,
    precisionScore: 0.871,
    recallScore: 0.842,
    f1Score: 0.856,
    daysAgo: 41,
    datasetVersion: 'synthetic-2026.07-r8',
    status: 'active',
    driftScore: 0.047,
    driftStatus: 'stable',
    notes:
      'Classifies which operating limit is reached first and maps it to a failure family. Synthetic validation set only.',
    notesAr:
      'يصنّف أول حد تشغيلي يُتجاوز ويربطه بعائلة العطل المناسبة. التحقق تم على بيانات اصطناعية فقط.',
  },
  {
    key: 'dna-matcher',
    name: 'Failure DNA Similarity',
    nameAr: 'مطابقة بصمات الأعطال',
    version: '1.2.1',
    task: 'similarity_search',
    algorithm: 'Weighted Euclidean distance over a 10-dimension normalised signature',
    accuracy: 0.881,
    precisionScore: 0.902,
    recallScore: 0.79,
    f1Score: 0.842,
    daysAgo: 63,
    datasetVersion: 'dna-library-v1',
    status: 'active',
    driftScore: 0.018,
    driftStatus: 'stable',
    notes:
      'Deterministic and inspectable: every match can be decomposed per dimension. Library contains 14 curated synthetic patterns.',
    notesAr:
      'حتمية وقابلة للفحص: يمكن تفكيك كل تطابق إلى أبعاده. تحتوي المكتبة على ١٤ نمطًا اصطناعيًا منسّقًا.',
  },
  {
    key: 'load-forecaster',
    name: 'Load Forecaster',
    nameAr: 'متنبئ الأحمال',
    version: '3.1.2',
    task: 'time_series_forecast',
    algorithm: 'Physics-informed diurnal + seasonal harmonics with temperature response',
    accuracy: 0.938,
    precisionScore: 0.921,
    recallScore: 0.907,
    f1Score: 0.914,
    daysAgo: 12,
    datasetVersion: 'synthetic-2026.08-r3',
    status: 'active',
    driftScore: 0.026,
    driftStatus: 'stable',
    notes:
      'Forecast and realised series come from one model, so the two curves are continuous at t=0 by construction.',
    notesAr:
      'التوقع والقيم المحققة يخرجان من نموذج واحد، لذا يلتقي المنحنيان عند اللحظة صفر بشكل متصل بحكم البناء.',
  },
  {
    key: 'rul-estimator',
    name: 'Remaining Useful Life Estimator',
    nameAr: 'مقدّر العمر المتبقي',
    version: '0.9.4',
    task: 'remaining_useful_life',
    algorithm: 'Montsinger thermal ageing law applied to live top-oil temperature',
    accuracy: 0.802,
    precisionScore: 0.784,
    recallScore: 0.771,
    f1Score: 0.777,
    daysAgo: 78,
    datasetVersion: 'synthetic-2026.06-r2',
    status: 'staging',
    driftScore: 0.112,
    driftStatus: 'watch',
    notes:
      'Pre-production. Ageing doubles for roughly every 6 °C above rating; estimates are indicative and should not drive procurement.',
    notesAr:
      'قيد ما قبل الإنتاج. يتضاعف التقادم لكل نحو ٦ درجات فوق التصنيف، والتقديرات إرشادية ولا تصلح لاتخاذ قرارات شراء.',
  },
  {
    key: 'anomaly-detector',
    name: 'Twin Deviation Detector',
    nameAr: 'كاشف انحراف التوأم الرقمي',
    version: '1.8.0',
    task: 'anomaly_detection',
    algorithm: 'Directional residual against the unperturbed digital twin',
    accuracy: 0.867,
    precisionScore: 0.849,
    recallScore: 0.821,
    f1Score: 0.835,
    daysAgo: 34,
    datasetVersion: 'synthetic-2026.07-r8',
    status: 'active',
    driftScore: 0.058,
    driftStatus: 'stable',
    notes:
      'Only adverse excursions score as anomalies — running cooler or lighter than expected is not flagged.',
    notesAr:
      'تُحتسب الانحرافات الضارة فقط، أما التشغيل بحرارة أو حمل أقل من المتوقع فلا يُعد شذوذًا.',
  },
]

// ─────────────────────────────────────────────────────────────────────────────
// Built-in what-if scenarios (§6)
// ─────────────────────────────────────────────────────────────────────────────

export interface ScenarioSeed {
  key: string
  name: string
  nameAr: string
  description: string
  descriptionAr: string
  category: string
  icon: string
  loadDeltaPct?: number
  solarDeltaPct?: number
  windDeltaPct?: number
  tempDeltaC?: number
  assetOutage?: boolean
  lineOutage?: boolean
  batteryOutage?: boolean
  evSurgeMw?: number
  industrialMw?: number
  durationMin: number
}

export const SCENARIOS: ScenarioSeed[] = [
  {
    key: 'transformer_failure',
    name: 'Transformer failure',
    nameAr: 'عطل محول',
    description: 'Take the selected transformer out of service and let its load fall on its neighbours.',
    descriptionAr: 'إخراج المحول المحدد من الخدمة وترك حمله ينتقل إلى المحولات المجاورة.',
    category: 'outage',
    icon: 'transformer',
    assetOutage: true,
    durationMin: 180,
  },
  {
    key: 'load_increase_30',
    name: '30 % load increase',
    nameAr: 'زيادة الحمل ٣٠٪',
    description: 'Raise demand across the selected scope by 30 % — an unplanned block or a forecast miss.',
    descriptionAr: 'رفع الطلب في النطاق المحدد بنسبة ٣٠٪ نتيجة كتلة غير مخططة أو خطأ في التوقع.',
    category: 'demand',
    icon: 'trending-up',
    loadDeltaPct: 30,
    durationMin: 120,
  },
  {
    key: 'solar_drop_40',
    name: 'Solar production −40 %',
    nameAr: 'انخفاض الإنتاج الشمسي ٤٠٪',
    description: 'Cloud or dust removes 40 % of photovoltaic output while demand holds.',
    descriptionAr: 'تزيل السحب أو الغبار ٤٠٪ من الإنتاج الكهروضوئي مع بقاء الطلب كما هو.',
    category: 'renewable',
    icon: 'solar',
    solarDeltaPct: -40,
    durationMin: 180,
  },
  {
    key: 'extreme_heat',
    name: 'Extreme heat wave',
    nameAr: 'موجة حر شديدة',
    description: 'Add 6 °C to ambient temperature — raising cooling demand and derating both PV and transformers.',
    descriptionAr: 'إضافة ٦ درجات مئوية لحرارة الجو، مما يرفع أحمال التبريد ويخفض أداء الألواح والمحولات معًا.',
    category: 'weather',
    icon: 'thermometer',
    tempDeltaC: 6,
    durationMin: 360,
  },
  {
    key: 'transmission_line_failure',
    name: 'Transmission line failure',
    nameAr: 'عطل خط نقل',
    description: 'Trip the transmission circuits in scope and re-evaluate the remaining paths.',
    descriptionAr: 'فصل دوائر النقل ضمن النطاق وإعادة تقييم المسارات المتبقية.',
    category: 'outage',
    icon: 'line',
    lineOutage: true,
    durationMin: 240,
  },
  {
    key: 'battery_failure',
    name: 'Battery storage failure',
    nameAr: 'عطل تخزين البطاريات',
    description: 'Remove battery storage from the balance, exposing the evening ramp.',
    descriptionAr: 'إخراج تخزين البطاريات من التوازن، مما يكشف الصعود المسائي.',
    category: 'outage',
    icon: 'battery',
    batteryOutage: true,
    durationMin: 240,
  },
  {
    key: 'ev_surge',
    name: 'Sudden EV charging demand',
    nameAr: 'ارتفاع مفاجئ في شحن المركبات الكهربائية',
    description: 'Add 220 MW of uncoordinated fast-charging demand at the hubs in scope.',
    descriptionAr: 'إضافة ٢٢٠ ميجاواط من طلب الشحن السريع غير المنسق في المراكز ضمن النطاق.',
    category: 'demand',
    icon: 'ev',
    evSurgeMw: 220,
    durationMin: 90,
  },
  {
    key: 'industrial_spike',
    name: 'Industrial load spike',
    nameAr: 'قفزة في الحمل الصناعي',
    description: 'Add 380 MW of industrial process load in a single step.',
    descriptionAr: 'إضافة ٣٨٠ ميجاواط من أحمال العمليات الصناعية دفعة واحدة.',
    category: 'demand',
    icon: 'industry',
    industrialMw: 380,
    durationMin: 120,
  },
  {
    key: 'renewable_surge',
    name: 'Renewable generation surge',
    nameAr: 'فائض في التوليد المتجدد',
    description: 'Push solar and wind 35 % above forecast, testing the grid for over-generation instead of scarcity.',
    descriptionAr: 'رفع إنتاج الشمس والرياح ٣٥٪ فوق التوقع لاختبار الشبكة أمام الفائض بدل الشح.',
    category: 'renewable',
    icon: 'wind',
    solarDeltaPct: 35,
    windDeltaPct: 35,
    durationMin: 180,
  },
  {
    key: 'heatwave_and_surge',
    name: 'Heat wave with industrial surge',
    nameAr: 'موجة حر مع ارتفاع صناعي',
    description:
      'The compound event NABDH was designed for: high ambient temperature and an unplanned demand block at the same time.',
    descriptionAr:
      'الحدث المركّب الذي صُمم نَبْض لأجله: حرارة محيطة مرتفعة وكتلة طلب غير مخططة في الوقت نفسه.',
    category: 'compound',
    icon: 'alert',
    tempDeltaC: 1.75,
    loadDeltaPct: 22,
    durationMin: 180,
  },
]

// ─────────────────────────────────────────────────────────────────────────────
// Integration catalogue (§27, §55)
// ─────────────────────────────────────────────────────────────────────────────

export interface IntegrationSeed {
  key: string
  name: string
  nameAr: string
  category: string
  protocol: string
  description: string
  descriptionAr: string
  status: string
  direction: string
}

/**
 * HONESTY NOTE (§55): only the internal simulation layer is actually wired up in this
 * build. Everything else is an adapter slot with a defined contract — listed as
 * "available" where the transport exists in the codebase, "planned" otherwise.
 */
export const INTEGRATIONS: IntegrationSeed[] = [
  {
    key: 'simulation-layer',
    name: 'NABDH Simulation Layer',
    nameAr: 'طبقة المحاكاة في نَبْض',
    category: 'internal',
    protocol: 'in-process',
    description: 'The deterministic digital twin that generates all telemetry in this build.',
    descriptionAr: 'التوأم الرقمي الحتمي الذي يولّد جميع القياسات في هذه النسخة.',
    status: 'connected',
    direction: 'inbound',
  },
  {
    key: 'rest-api',
    name: 'REST Ingestion API',
    nameAr: 'واجهة الإدخال REST',
    category: 'transport',
    protocol: 'HTTPS / JSON',
    description: 'Authenticated REST endpoints for batch telemetry and asset synchronisation.',
    descriptionAr: 'نقاط REST موثّقة لإدخال القياسات دفعيًا ومزامنة الأصول.',
    status: 'available',
    direction: 'inbound',
  },
  {
    key: 'sse-stream',
    name: 'Server-Sent Events Stream',
    nameAr: 'بث الأحداث من الخادم',
    category: 'transport',
    protocol: 'SSE',
    description: 'Live push channel used by the Command Center and Control Room views.',
    descriptionAr: 'قناة بث مباشر تستخدمها شاشات مركز التحكم وغرفة العمليات.',
    status: 'connected',
    direction: 'outbound',
  },
  {
    key: 'scada',
    name: 'SCADA',
    nameAr: 'سكادا',
    category: 'operations',
    protocol: 'IEC 60870-5-104',
    description: 'Real-time measurements and breaker status from the control system.',
    descriptionAr: 'القياسات اللحظية وحالة القواطع من نظام التحكم.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'ems',
    name: 'EMS',
    nameAr: 'نظام إدارة الطاقة',
    category: 'operations',
    protocol: 'ICCP / TASE.2',
    description: 'State estimation, dispatch and reserve data from energy management.',
    descriptionAr: 'تقدير الحالة والتوزيع وبيانات الاحتياطي من نظام إدارة الطاقة.',
    status: 'planned',
    direction: 'bidirectional',
  },
  {
    key: 'dms',
    name: 'DMS',
    nameAr: 'نظام إدارة التوزيع',
    category: 'operations',
    protocol: 'CIM / IEC 61968',
    description: 'Distribution network model and switching state.',
    descriptionAr: 'نموذج شبكة التوزيع وحالة المفاتيح.',
    status: 'planned',
    direction: 'bidirectional',
  },
  {
    key: 'ami',
    name: 'AMI / Smart Meters',
    nameAr: 'العدادات الذكية',
    category: 'metering',
    protocol: 'DLMS/COSEM',
    description: 'Interval consumption data for demand disaggregation.',
    descriptionAr: 'بيانات الاستهلاك الفترية لتفكيك الطلب.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'iot-mqtt',
    name: 'IoT Sensor Bus',
    nameAr: 'ناقل مستشعرات إنترنت الأشياء',
    category: 'sensing',
    protocol: 'MQTT 5',
    description: 'High-frequency condition monitoring from retrofitted sensors.',
    descriptionAr: 'مراقبة الحالة عالية التردد من مستشعرات مضافة.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'opc-ua',
    name: 'OPC-UA Gateway',
    nameAr: 'بوابة OPC-UA',
    category: 'sensing',
    protocol: 'OPC-UA',
    description: 'Plant-level process data from generation and industrial customers.',
    descriptionAr: 'بيانات العمليات على مستوى المحطات من التوليد والعملاء الصناعيين.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'weather-api',
    name: 'Weather Service',
    nameAr: 'خدمة الأرصاد',
    category: 'external',
    protocol: 'HTTPS / JSON',
    description: 'Numerical weather prediction feeding load and renewable forecasts.',
    descriptionAr: 'التنبؤ الجوي العددي الذي يغذي توقعات الأحمال والمتجددة.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'gis',
    name: 'GIS',
    nameAr: 'نظم المعلومات الجغرافية',
    category: 'external',
    protocol: 'WFS / GeoJSON',
    description: 'Authoritative asset geometry and network connectivity.',
    descriptionAr: 'الهندسة الجغرافية المعتمدة للأصول وترابط الشبكة.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'sap-pm',
    name: 'SAP Plant Maintenance',
    nameAr: 'صيانة المنشآت SAP',
    category: 'enterprise',
    protocol: 'OData',
    description: 'Work orders, notifications and maintenance history.',
    descriptionAr: 'أوامر العمل والإشعارات وسجل الصيانة.',
    status: 'planned',
    direction: 'bidirectional',
  },
  {
    key: 'renewable-scada',
    name: 'Renewable Plant SCADA',
    nameAr: 'سكادا محطات المتجددة',
    category: 'operations',
    protocol: 'IEC 61850',
    description: 'Inverter and turbine level telemetry from solar and wind plants.',
    descriptionAr: 'قياسات على مستوى العاكسات والتوربينات من محطات الشمس والرياح.',
    status: 'planned',
    direction: 'inbound',
  },
  {
    key: 'bess-ems',
    name: 'Battery EMS',
    nameAr: 'نظام إدارة البطاريات',
    category: 'operations',
    protocol: 'Modbus TCP',
    description: 'State of charge, available power and thermal state of storage fleets.',
    descriptionAr: 'حالة الشحن والقدرة المتاحة والحالة الحرارية لأساطيل التخزين.',
    status: 'planned',
    direction: 'bidirectional',
  },
  {
    key: 'notification-webhook',
    name: 'Notification Webhook',
    nameAr: 'ويب هوك الإشعارات',
    category: 'transport',
    protocol: 'HTTPS',
    description: 'Outbound alert delivery to email, SMS and paging gateways.',
    descriptionAr: 'إرسال التنبيهات إلى بوابات البريد والرسائل النصية والنداء.',
    status: 'available',
    direction: 'outbound',
  },
  {
    key: 'csv-import',
    name: 'CSV Import',
    nameAr: 'استيراد CSV',
    category: 'transport',
    protocol: 'File',
    description: 'Bulk historical import for backfilling asset and reading history.',
    descriptionAr: 'استيراد تاريخي دفعي لتعبئة سجلات الأصول والقياسات.',
    status: 'available',
    direction: 'inbound',
  },
]

// ─────────────────────────────────────────────────────────────────────────────
// Tunable settings (§42 — "make the weights configurable")
// ─────────────────────────────────────────────────────────────────────────────

export interface SettingSeed {
  key: string
  value: string
  valueType: string
  groupKey: string
  label: string
  labelAr: string
  description: string
  descriptionAr: string
  minValue?: number
  maxValue?: number
}

export const SETTINGS: SettingSeed[] = [
  {
    key: 'risk.weight.anomaly',
    value: '0.22',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Anomaly weight',
    labelAr: 'وزن الشذوذ',
    description: 'How much a deviation from the digital twin contributes to the stress index.',
    descriptionAr: 'مقدار مساهمة الانحراف عن التوأم الرقمي في مؤشر الإجهاد.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.weight.dna',
    value: '0.24',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Failure DNA weight',
    labelAr: 'وزن بصمة العطل',
    description: 'How much resemblance to a historical failure contributes to the stress index.',
    descriptionAr: 'مقدار مساهمة التشابه مع عطل تاريخي في مؤشر الإجهاد.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.weight.load',
    value: '0.26',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Loading weight',
    labelAr: 'وزن التحميل',
    description: 'How much loading above the stress floor contributes to the stress index.',
    descriptionAr: 'مقدار مساهمة التحميل فوق عتبة الإجهاد في المؤشر.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.weight.thermal',
    value: '0.19',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Thermal weight',
    labelAr: 'وزن الحرارة',
    description: 'How much temperature relative to the asset rating contributes.',
    descriptionAr: 'مقدار مساهمة الحرارة نسبةً إلى تصنيف الأصل.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.weight.weather',
    value: '0.09',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Weather weight',
    labelAr: 'وزن الطقس',
    description: 'How much ambient heat and dust contribute to the stress index.',
    descriptionAr: 'مقدار مساهمة حرارة الجو والغبار في مؤشر الإجهاد.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.amplifier.health',
    value: '0.35',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Condition amplifier',
    labelAr: 'مُضخّم الحالة',
    description: 'How strongly poor asset condition amplifies the stress index.',
    descriptionAr: 'مدى تضخيم حالة الأصل السيئة لمؤشر الإجهاد.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.amplifier.network',
    value: '0.15',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Consequence amplifier',
    labelAr: 'مُضخّم الأثر',
    description: 'How strongly the number of customers behind an asset amplifies its risk.',
    descriptionAr: 'مدى تضخيم عدد المشتركين خلف الأصل لدرجة خطره.',
    minValue: 0,
    maxValue: 1,
  },
  {
    key: 'risk.gamma',
    value: '1.15',
    valueType: 'number',
    groupKey: 'risk',
    label: 'Stress convexity',
    labelAr: 'تحدّب الإجهاد',
    description: 'Exponent applied to the stress index; above 1 makes high stress dominate.',
    descriptionAr: 'الأس المطبق على مؤشر الإجهاد؛ أكبر من ١ يجعل الإجهاد العالي مهيمنًا.',
    minValue: 0.5,
    maxValue: 2,
  },
  {
    key: 'alert.threshold.control_center',
    value: '70',
    valueType: 'number',
    groupKey: 'escalation',
    label: 'Control centre threshold',
    labelAr: 'عتبة مركز التحكم',
    description: 'Risk score at which an alert is raised to the control centre.',
    descriptionAr: 'درجة الخطر التي يُرفع عندها التنبيه إلى مركز التحكم.',
    minValue: 0,
    maxValue: 100,
  },
  {
    key: 'alert.threshold.supervisor',
    value: '85',
    valueType: 'number',
    groupKey: 'escalation',
    label: 'Supervisor threshold',
    labelAr: 'عتبة المشرف',
    description: 'Risk score at which an alert is escalated to a supervisor.',
    descriptionAr: 'درجة الخطر التي يُصعّد عندها التنبيه إلى المشرف.',
    minValue: 0,
    maxValue: 100,
  },
  {
    key: 'alert.threshold.emergency',
    value: '95',
    valueType: 'number',
    groupKey: 'escalation',
    label: 'Emergency threshold',
    labelAr: 'عتبة الطوارئ',
    description: 'Risk score at which emergency escalation is triggered.',
    descriptionAr: 'درجة الخطر التي يُفعّل عندها تصعيد الطوارئ.',
    minValue: 0,
    maxValue: 100,
  },
  {
    key: 'prediction.horizon.minutes',
    value: '180',
    valueType: 'number',
    groupKey: 'prediction',
    label: 'Prediction horizon',
    labelAr: 'أفق التنبؤ',
    description: 'How far ahead the digital twin is walked when looking for limit breaches.',
    descriptionAr: 'المدى الزمني الذي يُشغَّل فيه التوأم الرقمي بحثًا عن تجاوز الحدود.',
    minValue: 30,
    maxValue: 1440,
  },
  {
    key: 'prediction.step.minutes',
    value: '5',
    valueType: 'number',
    groupKey: 'prediction',
    label: 'Forward step',
    labelAr: 'خطوة التقدم',
    description: 'Coarse step of the forward walk; the crossing is then refined to the minute.',
    descriptionAr: 'الخطوة التقريبية للمسح المستقبلي، ثم تُدقّق لحظة التجاوز إلى الدقيقة.',
    minValue: 1,
    maxValue: 30,
  },
  {
    key: 'telemetry.tick.ms',
    value: '3000',
    valueType: 'number',
    groupKey: 'runtime',
    label: 'Live tick interval',
    labelAr: 'فاصل التحديث المباشر',
    description: 'How often the live stream pushes a new grid snapshot.',
    descriptionAr: 'معدل دفع لقطة جديدة للشبكة عبر البث المباشر.',
    minValue: 1000,
    maxValue: 60000,
  },
  {
    key: 'platform.demo_data',
    value: 'true',
    valueType: 'boolean',
    groupKey: 'runtime',
    label: 'Demo data banner',
    labelAr: 'شريط بيانات العرض',
    description: 'Shows the "simulated data" marker across the interface. Required for the hackathon build.',
    descriptionAr: 'يعرض علامة «بيانات محاكاة» عبر الواجهة، وهي مطلوبة في نسخة الهاكاثون.',
  },
]

export interface EscalationSeed {
  name: string
  nameAr: string
  minRisk: number
  maxRisk: number
  targetRole: string
  channels: string
  level: number
  delayMin: number
}

export const ESCALATION_RULES: EscalationSeed[] = [
  {
    name: 'Control centre notification',
    nameAr: 'إشعار مركز التحكم',
    minRisk: 70,
    maxRisk: 85,
    targetRole: 'control_operator',
    channels: 'dashboard,email',
    level: 1,
    delayMin: 0,
  },
  {
    name: 'Supervisor escalation',
    nameAr: 'تصعيد إلى المشرف',
    minRisk: 85,
    maxRisk: 95,
    targetRole: 'engineer',
    channels: 'dashboard,email,sms',
    level: 2,
    delayMin: 5,
  },
  {
    name: 'Emergency escalation',
    nameAr: 'تصعيد طوارئ',
    minRisk: 95,
    maxRisk: 100,
    targetRole: 'executive',
    channels: 'dashboard,email,sms,webhook',
    level: 3,
    delayMin: 0,
  },
]

export const DAY_MS = DAY
