#!/usr/bin/env python3
"""Seed ONE coherent demo customer so the whole CRA<->IACE frontend journey is
walkable: CompanyProfile (complete) + an IACE CE risk-assessment project
(Kistenhubgeraet, with components + hazards + mitigations) + a CRA project
(intake + scope-check) + a persisted CRA assessment snapshot driven by faked
repo findings + the machine's networked components + its safety functions.

Run inside the backend container (reaches both APIs):
  docker exec -i bp-compliance-backend python3 - < scripts/seed_demo_customer.py

Idempotency: not enforced — re-running creates duplicates. Resilient: each step
prints its outcome and continues on error. The source-repo layer is FAKED
(findings below) so the entire frontend can be seen once.
"""
import json
import urllib.request

TENANT = "9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
BACKEND = "http://localhost:8002"
AISDK = "http://ai-compliance-sdk:8090"
H = {"Content-Type": "application/json", "X-Tenant-ID": TENANT, "X-Tenant-Id": TENANT}


def call(method, url, body=None):
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, headers=H, method=method)
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            txt = r.read().decode()
            return r.getcode(), (json.loads(txt) if txt.strip() else {})
    except urllib.error.HTTPError as e:
        return e.code, {"error": e.read().decode()[:300]}
    except Exception as e:
        return 0, {"error": str(e)}


def step(label, method, url, body=None):
    code, resp = call(method, url, body)
    ok = 200 <= code < 300
    rid = resp.get("id") if isinstance(resp, dict) else None
    print(("  OK " if ok else "  !! ") + f"[{code}] {label}" + (f" id={rid}" if rid else "")
          + ("" if ok else f" {resp.get('error','')[:160]}"))
    return resp if ok else None


print("== 1. CompanyProfile ==")
step("company-profile", "POST", f"{BACKEND}/api/v1/company-profile", {
    "company_name": "DEMO Kistenhub GmbH", "legal_form": "GmbH", "industry": "Maschinenbau",
    "founded_year": 2015, "business_model": "B2B", "company_size": "medium", "employee_count": "50-99",
    "headquarters_country": "DE", "headquarters_city": "Augsburg", "is_data_controller": True,
    "is_complete": True,
})

print("== 2. IACE project (CE risk assessment) ==")
proj = step("iace project", "POST", f"{AISDK}/sdk/v1/iace/projects", {
    "machine_name": "Kistenhubgeraet Demo", "machine_type": "Hydraulischer Kistenhubwagen (vernetzt)",
    "manufacturer": "DEMO Kistenhub GmbH",
    "description": "Palettierte-Gueter-Hubgeraet mit IoT-Modul, App-Parametrierung und Fernwartung.",
    "narrative_text": "Zwei-Hub-System, hydraulisch, mit vernetzter Steuerung und Fernzugriff.",
    "ce_marking_target": "Maschinenverordnung (EU) 2023/1230",
})
pid = proj.get("id") if proj else None
if not pid:  # IACE create response may not surface "id" — fall back to the list
    _, lst = call("GET", f"{AISDK}/sdk/v1/iace/projects")
    for p in (lst.get("projects") if isinstance(lst, dict) else []) or []:
        if p.get("machine_name") == "Kistenhubgeraet Demo":
            pid = p.get("id")
            break
    print(f"  (fallback) iace project id={pid}")

comp_ids = {}
if pid:
    print("== 3. IACE components ==")
    for c in [
        {"name": "Hub-Steuerung (SPS)", "component_type": "controller", "is_safety_relevant": True, "is_networked": True},
        {"name": "Bedienpanel (HMI)", "component_type": "hmi", "is_networked": True},
        {"name": "Hydraulikpumpe", "component_type": "hydraulic", "is_safety_relevant": True},
        {"name": "Fernwartungs-Gateway", "component_type": "gateway", "is_networked": True},
    ]:
        c["project_id"] = pid
        r = step(f"component {c['name']}", "POST", f"{AISDK}/sdk/v1/iace/projects/{pid}/components", c)
        if r:
            comp_ids[c["name"]] = r.get("id")

    print("== 4. IACE hazards + mitigations ==")
    hazards = [
        {"name": "Quetschen zwischen Last und Rahmen", "category": "Mechanische Gefaehrdungen",
         "scenario": "Bediener greift bei Hubbewegung zwischen Last und Rahmen",
         "comp": "Hub-Steuerung (SPS)", "measure": "Zweihandschaltung + trennende Schutzeinrichtung (PL d)"},
        {"name": "Lastabsturz durch Ueberlast", "category": "Mechanische Gefaehrdungen",
         "scenario": "Ueberschreiten der zulaessigen Last fuehrt zum Absturz",
         "comp": "Hydraulikpumpe", "measure": "Ueberlastsicherung / Lastmomentbegrenzer"},
        {"name": "Schneiden an scharfen Kanten", "category": "Mechanische Gefaehrdungen",
         "scenario": "Kontakt mit scharfen Gehaeusekanten bei Wartung",
         "comp": "Bedienpanel (HMI)", "measure": "Brechen oder Runden aller zugaenglichen Kanten"},
    ]
    for hz in hazards:
        body = {"project_id": pid, "name": hz["name"], "category": hz["category"], "scenario": hz["scenario"]}
        cid = comp_ids.get(hz["comp"])
        if cid:
            body["component_id"] = cid
        r = step(f"hazard {hz['name']}", "POST", f"{AISDK}/sdk/v1/iace/projects/{pid}/hazards", body)
        hid = r.get("id") if r else None
        if hid:
            step("  mitigation", "POST", f"{AISDK}/sdk/v1/iace/projects/{pid}/hazards/{hid}/mitigations",
                 {"hazard_id": hid, "reduction_type": "design_measure", "name": hz["measure"]})

print("== 5. CRA project + intake + scope-check ==")
cra = step("cra project", "POST", f"{BACKEND}/api/v1/cra/projects",
           {"name": "DEMO Kistenhub CRA", "description": "Cyber-Risikobeurteilung fuer das Kistenhubgeraet"})
cra_id = cra.get("id") if cra else None
if cra_id:
    step("intake (flags)", "PATCH", f"{BACKEND}/api/v1/cra/projects/{cra_id}", {
        "intended_use": "Vernetztes Kistenhubgeraet mit App-Parametrierung und Fernwartung",
        "connected_to_internet": True, "has_software_updates": True, "has_firmware": True,
        "processes_personal_data": False, "is_critical_infra_supplier": False,
    })
    step("scope-check", "POST", f"{BACKEND}/api/v1/cra/projects/{cra_id}/scope-check")

    print("== 6. CRA assessment snapshot (faked repo findings + components + safety functions) ==")
    snap_body = {
        "findings": [
            {"id": "REPO-001", "title": "Default-Passwort in Fernsteuer-UI", "cwe": "CWE-259", "severity": "critical", "location": "remote-ui/login"},
            {"id": "REPO-002", "title": "Schwache TLS-Konfiguration", "cwe": "CWE-327", "severity": "high", "location": "telemetry/tls"},
            {"id": "REPO-003", "title": "Veraltete Abhaengigkeit libmodbus", "category": "dependency", "cwe": "CWE-1104", "severity": "high", "location": "deps/libmodbus"},
        ],
        "components": [
            {"name": "Hub-Steuerung (SPS)", "component_class": "controller", "networked": True},
            {"name": "Bedienpanel (HMI)", "component_class": "hmi", "networked": True},
            {"name": "Fernwartungs-Gateway", "component_class": "gateway", "networked": True},
        ],
        "safety_functions": [
            {"name": "Zweihandschaltung + trennende Schutzeinrichtung", "hazard": "Quetschen zwischen Last und Rahmen", "kind": "prevent_unexpected_actuation"},
            {"name": "Ueberlastsicherung / Lastmomentbegrenzer", "hazard": "Lastabsturz durch Ueberlast", "kind": "signal_integrity"},
        ],
        "weights": {"access": "high", "data": "high"},
    }
    step("assess-snapshot", "POST", f"{BACKEND}/api/v1/cra/projects/{cra_id}/assess-snapshot", snap_body)

print("\nDONE. tenant=%s | iace_project=%s | cra_project=%s" % (TENANT, pid, cra_id))
