# ruff: noqa
# mypy: ignore-errors
"""Environmental stress test — does the architecture work OUTSIDE cyber? (Phase Ω)

Every prior journey lived in the cyber family (CRA / MaschinenVO / TISAX / ISO 27001 / OEM / Tender —
all infosec, software, product cybersecurity). This is the first NON-cyber stress test: substance flows,
emissions, water, chemicals, energy, circularity. The claim under test is NOT "we built an environmental
cluster" but "RS-005 carries an entirely different mental model UNCHANGED — only new DATA, zero runtime".

It runs ISO 14001 (an EMS, as a Company Profile, Welt-1) -> an Environmental target through the SAME
engines used for ISO 27001 -> CRA, and asks the SAME question: which environmental capabilities are
still missing? Plus the new quality question (rejected_assumptions): which capabilities does ISO 14001
typically NOT produce? And it runs the Journey Matcher to confirm it stays domain-agnostic.

Synthetic, no real names. Non-runtime -> no deploy.
Run:  cd backend-compliance && PYTHONPATH=. python3 reference_scenarios/environmental_stress_test.py
"""
from __future__ import annotations

import os
import yaml

from compliance.company import (
    CompanyContext, Certification, CapabilityMappingEntry, build_company_profile,
)
from compliance.reasoning.enums import Confidence
from compliance.transition_reasoning import (
    TransitionContext, TransitionGoal, TargetRequirement, assess_transition, CoverageStatus,
)
from compliance.journey_matcher import JourneySignature, match_journeys

OUT = []


def w(s=""):
    OUT.append(s)


_K = os.path.join(os.path.dirname(__file__), "..", "knowledge", "transition_patterns")


def _load(name):
    return yaml.safe_load(open(os.path.join(_K, name), encoding="utf-8"))


ENV = _load("transition_pattern_iso14001_to_environmental_v1.yaml")
mgmt = [a["capability"] for a in ENV["likely_covered"]]          # what ISO 14001 DOES give (Welt-1)
concrete = [d["capability"] for d in ENV["delta_requirements"]]  # what it does NOT give (the delta)

# ── Company Profile: ISO 14001 -> the management capabilities only (NO concrete evidence) ────
profile = build_company_profile(
    CompanyContext(company_id="env", certifications=[Certification(certification_id="ISO14001")]),
    {"ISO14001": CapabilityMappingEntry(capability_ids=mgmt, confidence=Confidence.MEDIUM)})

# ── SAME engine as ISO 27001 -> CRA: required = management + concrete; delta = what's missing ─
reqs = [TargetRequirement(capability_id=c) for c in mgmt + concrete]
assess = assess_transition(TransitionContext(company_id="env", target=TransitionGoal(target_id="Environmental")), reqs, profile)
covered = sorted({c.capability_id for c in assess.coverage if c.status != CoverageStatus.MISSING})
delta = sorted({c.capability_id for c in assess.coverage if c.status == CoverageStatus.MISSING})

# ── Journey Matcher: stays domain-agnostic? cyber journeys must score ~0 on an env delta ─────
def _sig(name, label):
    p = _load(name)
    return JourneySignature(journey_id=p.get("id", name), label=label,
                            capability_pattern=[d["capability"] for d in p["delta_requirements"]])
journeys = [
    _sig("transition_pattern_iso14001_to_environmental_v1.yaml", "ISO14001 -> Environmental"),
    _sig("transition_pattern_iso27001_to_cra_maschinenvo_v1.yaml", "ISO27001 -> CRA + MaschinenVO"),
    _sig("transition_pattern_isms_to_tisax_v1.yaml", "ISMS -> TISAX"),
]
match = match_journeys(delta, journeys)

w("# Environmental Stress Test — funktioniert die Architektur AUSSERHALB von Cyber? (Phase Ω)")
w("")
w('_Erster Nicht-Cyber-Test. Nicht „wir bauen einen Umwelt-Cluster", sondern: trägt RS-005 ein völlig anderes Denkmodell (Stoffe/Emissionen/Wasser/Energie/Kreislauf) UNVERÄNDERT — nur neue DATEN, null Runtime-Code? ISO 14001 als Company Profile (Welt-1), dieselbe Engine wie ISO 27001 → CRA. Synthetisch, keine echten Namen._')
w("")
w("## 1. ISO 14001 als Company Profile — Management, nicht Evidence")
w("- ISO 14001 liefert **Umwelt-MANAGEMENT-Disziplin** (Welt-1, wahrscheinlich vorhanden): %s." % ", ".join("`%s`" % c for c in mgmt))
w("- Über **dieselbe** `assess_transition`-Engine wie im Cyber-Fall — **keine Zeile neuer Runtime-Code**, nur ein neues Pattern-YAML.")
w("")
w("## 2. RS-005 stellt dieselbe Frage: welche Umwelt-Capabilities fehlen?")
w("> %s" % assess.summary.headline)
w("- **Vermutlich vorhanden (Management):** %d — %s" % (len(covered), ", ".join("`%s`" % c for c in covered[:3]) + " …"))
w("- **Delta (konkrete Evidence, fehlt): %d Capabilities** — z. B. %s …" % (len(delta), ", ".join("`%s`" % c for c in delta[:4])))
w("- Capabilities sind **Verben** (capability-is-a-verb): `manage_chemical_substances`, `measure_air_emissions`, `issue_battery_passport` …")
w("")
w("## 3. Neue Qualitätsfrage — was erzeugt ISO 14001 typischerweise NICHT? _(rejected_assumptions, Welt-1/Welt-2)_")
for r in ENV["rejected_assumptions"]:
    w("- %s" % r)
w("")
w("→ Genau wie ISO 9001 → CRA: ein **Managementsystem** gibt die Disziplin, aber **nicht die konkrete substanz-/produktspezifische Evidence**. Die Welt-1/Welt-2-Trennung bleibt erhalten.")
w("")
w("## 4. Journey Matcher bleibt domänen-agnostisch")
w("> %s" % match.headline)
w("| Journey | erklärt das Umwelt-Delta |")
w("|---|---|")
for m in match.matches:
    w("| %s | %d%% |" % (m.label, round(m.score * 100)))
w("")
w("→ Die **Cyber-Journeys erklären 0 %** des Umwelt-Deltas — der Matcher rät nicht, er erklärt nur, was das Delta wirklich beschreibt.")
w("")
w("## Befund")
w("")
w('> **Ein völlig anderes Denkmodell (Umwelt) lief durch `Reality → Evidence → Capability → Required → Delta → Journey` ohne eine Zeile neuen Runtime-Code — nur ein neues Pattern-YAML + injizierte Required-Caps.** Das ist ein stärkerer Generalitätsbeweis als zehn weitere Cyber-Regelwerke: die Architektur ist nicht „Compliance/Cyber", sondern ein allgemeines Trägersystem. **%d neue Capability-Typen** (5 Management + %d konkrete Evidence) — in der Größenordnung der Cyber-Domänen, kein Granularitäts-Frühindikator. Architecture Stability: **0 neue Runtime-Klassen, 0 neue Pipeline.**' % (len(mgmt) + len(concrete), len(concrete)))
w("")

print("\n".join(OUT))
