#!/usr/bin/env python3
"""PGS 15:2025 Compliance Toetsing — Phoenix Metals v8.0"""

import json, os
from datetime import datetime
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml

JSON_PATH = '/root/.openclaw/workspace/pgs15-scanner/exports/scan_phoenix_metals_excel.json'
OUTPUT_PATH = '/root/projects/jg/2026-pgs15-phoenix-metals/deliverables/docx/PGS15_Compliance_Toetsing_Phoenix_Metals_v8.0.docx'
LOGO_PATH = '/root/projects/jg/assets/branding/jvg-logo-white-medium.png'

def hexcolor(r, g, b): return f"{r:02X}{g:02X}{b:02X}"

C_PRIMARY = hexcolor(0x00, 0x33, 0x66)
C_TEXT = hexcolor(0x1F, 0x29, 0x37)
C_SECONDARY = hexcolor(0x37, 0x41, 0x51)
C_BG = hexcolor(0xF8, 0xF9, 0xFA)
C_BORDER = hexcolor(0xE5, 0xE7, 0xEB)
C_SUCCESS = hexcolor(0x00, 0xA8, 0x59)
C_WARNING = hexcolor(0xF5, 0x9E, 0x0B)
C_DANGER = hexcolor(0xEF, 0x44, 0x44)
C_WHITE = hexcolor(0xFF, 0xFF, 0xFF)
C_ORANGE = hexcolor(0xFF, 0x6D, 0x00)

def shade(cell, color_hex):
    el = parse_xml(f'<w:shd {nsdecls("w")} w:fill="{color_hex}"/>')
    cell._tc.get_or_add_tcPr().append(el)

def add_border(cell):
    c = C_BORDER
    xml = (f'<w:tcBorders {nsdecls("w")}>'
           f'<w:top w:val="single" w:sz="4" w:space="0" w:color="{c}"/>'
           f'<w:left w:val="single" w:sz="4" w:space="0" w:color="{c}"/>'
           f'<w:bottom w:val="single" w:sz="4" w:space="0" w:color="{c}"/>'
           f'<w:right w:val="single" w:sz="4" w:space="0" w:color="{c}"/>'
           '</w:tcBorders>')
    cell._tc.get_or_add_tcPr().append(parse_xml(xml))

def hcell(cell, text, bg=C_PRIMARY, fg=C_WHITE, sz=9, bold=True, align=WD_ALIGN_PARAGRAPH.CENTER):
    cell.text = ""
    p = cell.paragraphs[0]; p.alignment = align
    r = p.add_run(text); r.bold = bold; r.font.size = Pt(sz)
    r.font.color.rgb = RGBColor(int(fg[0:2],16), int(fg[2:4],16), int(fg[4:6],16))
    shade(cell, bg)
    add_border(cell)

def dcell(cell, text, bg=None, fg=C_TEXT, sz=9, bold=False, align=WD_ALIGN_PARAGRAPH.LEFT):
    cell.text = ""
    p = cell.paragraphs[0]; p.alignment = align
    r = p.add_run(str(text)); r.bold = bold; r.font.size = Pt(sz)
    r.font.color.rgb = RGBColor(int(fg[0:2],16), int(fg[2:4],16), int(fg[4:6],16))
    if bg: shade(cell, bg)
    add_border(cell)

def para(doc, text, bold=False, sz=11, color=C_TEXT, align=WD_ALIGN_PARAGRAPH.LEFT, space=6):
    p = doc.add_paragraph(); p.alignment = align; p.paragraph_format.space_after = Pt(space)
    r = p.add_run(text); r.bold = bold; r.font.size = Pt(sz)
    r.font.color.rgb = RGBColor(int(color[0:2],16), int(color[2:4],16), int(color[4:6],16))

def heading(doc, text, level=1):
    h = doc.add_heading(text, level=level)
    for r in h.runs:
        r.font.color.rgb = RGBColor(0x00, 0x33, 0x66)
        r.font.size = Pt(16 if level==1 else 14 if level==2 else 12)

# ── LOAD ──
with open(JSON_PATH) as f:
    scan = json.load(f)

agg = scan.get('aggregatie', {})
per_stof = scan.get('per_stof', [])
comb = scan.get('combinatie', {})
comb_agg = comb.get('aggregatie', {})
v3 = scan.get('v3_compliance', {})

# ── DOC ──
doc = Document()
for s in doc.sections:
    s.top_margin = s.bottom_margin = Cm(2.5)
    s.left_margin = s.right_margin = Cm(2.5)

# ── 1. VOORBLAD ──
if os.path.exists(LOGO_PATH):
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
    p.add_run().add_picture(LOGO_PATH, width=Cm(2.0), height=Cm(1.8))

doc.add_paragraph()
p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run("PGS 15:2025 Compliance Toetsing"); r.bold=True; r.font.size=Pt(22); r.font.color.rgb=RGBColor(0x00,0x33,0x66)

p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run("Phoenix Metals — Opslag Gevaarlijke Stoffen"); r.bold=True; r.font.size=Pt(16); r.font.color.rgb=RGBColor(0x37,0x41,0x51)

doc.add_paragraph()
t = doc.add_table(rows=6, cols=2); t.alignment = WD_TABLE_ALIGNMENT.CENTER; t.style='Table Grid'
for i,(lbl,val) in enumerate([
    ("Project","PGS 15:2025 Compliance Toetsing — Phoenix Metals"),
    ("Locatie","Zaandam"),("Datum",datetime.now().strftime("%d-%m-%Y")),
    ("Versie","8.0"),("Status","Final"),
    ("Auteur","Kas (Director of Operations) — JvG Consultancy")
]):
    hcell(t.rows[i].cells[0], lbl, align=WD_ALIGN_PARAGRAPH.LEFT)
    dcell(t.rows[i].cells[1], val, sz=10)

doc.add_page_break()

# ── 2. INHOUD ──
heading(doc,"Inhoudsopgave")
for i in ["1. Samenvatting","2. Methodiek","3. Stofinventaris","4. Niveaubepaling per Stof",
          "5. Aggregatie-analyse","6. CMR-toetsing","7. Conformiteitsoordeel","8. Aanbevelingen",
          "9. Bronnenlijst","10. TierVerify Log"]:
    para(doc, i, sz=11, space=3)
doc.add_page_break()

# ── 3. SAMENVATTING ──
heading(doc,"1. Samenvatting")
totaal_kg = agg.get('totaal_kg',0)
geagg = agg.get('geaggregeerd_niveau','?')
catch = agg.get('catchall',False)
pk = agg.get('per_klasse',{})
cmr_stoffen = [s for s in per_stof if s.get('is_cmr')]

para(doc,f"Dit rapport presenteert de PGS 15:2025 compliance toetsing voor Phoenix Metals, Zaandam. "
     f"In totaal zijn {len(per_stof)} stoffen geanalyseerd met een gezamenlijke opslag van {totaal_kg:,.0f} kg.",sz=11,space=8)
para(doc,"Kernbevindingen:",bold=True,sz=11,space=4)
para(doc,f"• Geaggregeerd veiligheidsniveau: {geagg}",sz=11,space=3)
para(doc,f"• Catch-all (>1.000 kg): {'Ja — PGS 15 van toepassing op alle gevaarlijke stoffen' if catch else 'Nee'}",sz=11,space=3)
para(doc,f"• ADR 8 (corrosief): {pk.get('8',{}).get('totaal_kg',0):,.0f} kg — Niveau Basis (onbrandbaar, voetnoot c)",sz=11,space=3)
para(doc,f"• ADR 5.1 (oxiderend): {pk.get('5.1',{}).get('totaal_kg',0):,.0f} kg — Niveau C",sz=11,space=3)
para(doc,f"• ADR 6.1 (giftig): {pk.get('6.1',{}).get('totaal_kg',0):,.0f} kg — Niveau C",sz=11,space=3)
para(doc,f"• CMR-stoffen: {len(cmr_stoffen)} geïdentificeerd",sz=11,space=8)

# ── 4. METHODIEK ──
heading(doc,"2. Methodiek")
para(doc,"Toetsing conform PGS 15:2025 (Publicatie 565) — Opslag van verpakte gevaarlijke stoffen.",sz=11,space=8)
heading(doc,"2.1 Ondergrenzen (Tabel 2)",level=2)
para(doc,"Ondergrens = minimumhoeveelheid waarbij PGS 15:2025 van toepassing wordt. "
     "CMR-stoffen: 25 kg. ADR 5.1 VG II/III: 50 kg. ADR 6.1 VG II/III: 50 kg.",sz=11,space=8)
heading(doc,"2.2 Niveaudrempels (Tabel 6)",level=2)
para(doc,"Veiligheidsniveaus (C, B, A) op basis van hoeveelheid en ADR-klasse/VG. Strengste niveau is leidend.",sz=11,space=8)
heading(doc,"2.3 Aggregatie",level=2)
para(doc,"Stoffen met dezelfde ADR-klasse worden geaggregeerd. Catch-all: >1.000 kg totaal = PGS 15 van toepassing.",sz=11,space=8)
heading(doc,"2.4 Voetnoot c",level=2)
para(doc,"Onbrandbare ADR 8/9 VG II/III → Basisveiligheid, ongeacht hoeveelheid.",sz=11,space=8)
doc.add_page_break()

# ── 5. STOFINVENTARIS ──
heading(doc,"3. Stofinventaris")
t = doc.add_table(rows=1,cols=7); t.alignment=WD_TABLE_ALIGNMENT.CENTER; t.style='Table Grid'
for i,h in enumerate(["Stofnaam","CAS","ADR","VG","Hoeveelheid (kg)","H-zinnen","CMR"]):
    hcell(t.rows[0].cells[i],h,sz=9)

sorted_stof = sorted(per_stof, key=lambda s: (s.get('adr_klasse','ZZZ'), -s.get('hoeveelheid',0)))
for s in sorted_stof:
    row = t.add_row()
    dcell(row.cells[0],s.get('naam',''),sz=8)
    dcell(row.cells[1],s.get('cas',''),sz=8)
    dcell(row.cells[2],s.get('adr_klasse',''),sz=8,align=WD_ALIGN_PARAGRAPH.CENTER)
    dcell(row.cells[3],s.get('vg',''),sz=8,align=WD_ALIGN_PARAGRAPH.CENTER)
    dcell(row.cells[4],f"{s.get('hoeveelheid',0):,.0f}",sz=8,align=WD_ALIGN_PARAGRAPH.RIGHT)
    dcell(row.cells[5],s.get('h_zinnen',''),sz=7)
    cmr = s.get('is_cmr',False)
    dcell(row.cells[6],"⚠️ JA" if cmr else "Nee",sz=8,align=WD_ALIGN_PARAGRAPH.CENTER,bg=C_WARNING if cmr else None)
doc.add_page_break()

# ── 6. NIVEAUBEPALING ──
heading(doc,"4. Niveaubepaling per Stof")
for s in sorted_stof:
    n = s.get('strengste_niveau','?')
    para(doc,s.get('naam',''),bold=True,sz=11,space=2)
    d = f"ADR {s.get('adr_klasse','')} VG {s.get('vg','')} | {s.get('hoeveelheid',0):,.0f} kg | H: {s.get('h_zinnen','geen')} | "
    if s.get('is_cmr'): d += "CMR | "
    if s.get('voetnoot_c'): d += "Voetnoot c | "
    d += f"Niveau: {n}"
    para(doc,d,sz=10,color=C_SECONDARY,space=6)
doc.add_page_break()

# ── 7. AGGREGATIE ──
heading(doc,"5. Aggregatie-analyse")
para(doc,f"Totaal: {totaal_kg:,.0f} kg | Geaggregeerd niveau: {geagg}",sz=11,space=8)
t = doc.add_table(rows=1,cols=5); t.alignment=WD_TABLE_ALIGNMENT.CENTER; t.style='Table Grid'
for i,h in enumerate(["ADR-klasse","Aantal","Totaal (kg)","Zwaarste VG","Niveau"]):
    hcell(t.rows[0].cells[i],h,sz=10)
for kl in sorted(pk.keys()):
    info = pk[kl]; row = t.add_row()
    dcell(row.cells[0],kl,sz=10,align=WD_ALIGN_PARAGRAPH.CENTER,bold=True)
    dcell(row.cells[1],str(info.get('aantal',0)),sz=10,align=WD_ALIGN_PARAGRAPH.CENTER)
    dcell(row.cells[2],f"{info.get('totaal_kg',0):,.0f}",sz=10,align=WD_ALIGN_PARAGRAPH.RIGHT)
    zv = comb_agg.get(kl,{}).get('zwaarste_vg','II')
    dcell(row.cells[3],zv,sz=10,align=WD_ALIGN_PARAGRAPH.CENTER)
    n = comb_agg.get(kl,{}).get('niveau','?')
    dcell(row.cells[4],n,sz=10,align=WD_ALIGN_PARAGRAPH.CENTER,bold=True)
# Totaal
row = t.add_row()
for i,(txt) in enumerate(["TOTAAL",str(len(per_stof)),f"{totaal_kg:,.0f}","—",geagg]):
    dcell(row.cells[i],txt,bg=C_PRIMARY,fg=C_WHITE,bold=True,sz=10,align=WD_ALIGN_PARAGRAPH.CENTER)
doc.add_paragraph()
para(doc,"Voetnoot c: Onbrandbare ADR 8/9 VG II/III → Basisveiligheid (verklaart ADR 8 Basis-niveau ondanks grote hoeveelheden).",sz=10,color=C_SECONDARY,space=8)
doc.add_page_break()

# ── 8. CMR ──
heading(doc,"6. CMR-toetsing")
para(doc,"PGS 15:2025 ondergrens voor CMR-stoffen: 25 kg. Stoffen <25 kg vallen buiten PGS 15-scope voor opslag.",sz=11,space=8)
if cmr_stoffen:
    t = doc.add_table(rows=1,cols=5); t.alignment=WD_TABLE_ALIGNMENT.CENTER; t.style='Table Grid'
    for i,h in enumerate(["Stofnaam","H-zinnen","Hoeveelheid (kg)","Ondergrens","Status"]):
        hcell(t.rows[0].cells[i],h,sz=10)
    for s in cmr_stoffen:
        row = t.add_row(); h = s.get('hoeveelheid',0); io = h >= 25
        dcell(row.cells[0],s.get('naam',''),sz=9)
        dcell(row.cells[1],s.get('h_zinnen',''),sz=8)
        dcell(row.cells[2],f"{h:,.0f}",sz=9,align=WD_ALIGN_PARAGRAPH.RIGHT)
        dcell(row.cells[3],"25 kg",sz=9,align=WD_ALIGN_PARAGRAPH.CENTER)
        st = "⚠️ IN SCOPE (≥25 kg)" if io else "Buiten scope (<25 kg)"
        dcell(row.cells[4],st,sz=9,bg=C_WARNING if io else None,bold=True)
doc.add_page_break()

# ── 9. CONFORMITEIT ──
heading(doc,"7. Conformiteitsoordeel")
t = doc.add_table(rows=1,cols=4); t.alignment=WD_TABLE_ALIGNMENT.CENTER; t.style='Table Grid'
for i,h in enumerate(["Stofnaam","ADR-klasse","Niveau","PGS 15 Scope"]):
    hcell(t.rows[0].cells[i],h,sz=10)
for s in sorted_stof:
    row = t.add_row(); n = s.get('strengste_niveau','?'); io = n not in ('Buiten scope',)
    dcell(row.cells[0],s.get('naam',''),sz=9)
    dcell(row.cells[1],s.get('adr_klasse','Geen'),sz=9,align=WD_ALIGN_PARAGRAPH.CENTER)
    dcell(row.cells[2],n,sz=9,align=WD_ALIGN_PARAGRAPH.CENTER,bold=True)
    sc = "✅ In scope" if io else "Buiten scope"
    dcell(row.cells[3],sc,sz=9,align=WD_ALIGN_PARAGRAPH.CENTER)
doc.add_page_break()

# ── 10. AANBEVELINGEN ──
heading(doc,"8. Aanbevelingen")
for i,(titel,desc) in enumerate([
    ("Niveau C maatregelen","Implementeer alle verplichte maatregelen voor veiligheidsniveau C (PGS 15:2025 Hoofdstuk 7)."),
    ("CMR-registratie","Houd lijst bij van werknemers blootgesteld aan CMR-stoffen (Arbobesluit art. 4.2a)."),
    ("RI&E actualisatie","Werk RI&E bij met huidige opslaghoeveelheden en classificaties."),
    ("Voetnoot c stoffen","ADR 8/9 onbrandbaar → uitsluitend Basisveiligheidsmaatregelen."),
    ("ADR 5.1 opslag","H2O2 + Na-persulfate (300 kg) → Niveau C maatregelen vereist."),
    ("Periodieke toetsing","Herhaal PGS 15 toetsing bij wijzigingen in opslag."),
],1):
    para(doc,f"{i}. {titel}",bold=True,sz=11,space=2)
    para(doc,desc,sz=10,color=C_SECONDARY,space=6)
doc.add_page_break()

# ── 11. BRONNEN ──
heading(doc,"9. Bronnenlijst")
for b in [
    "[1] PGS 15:2025 — Opslag van verpakte gevaarlijke stoffen, Publicatie 565, VNG Realisatie",
    "[2] Arbeidsomstandighedenbesluit, Hoofdstuk 4, Paragraaf 2 (CMR-stoffen)",
    "[3] ADR — Accord européen relatif au transport international des marchandises Dangereuses par Route",
    "[4] CLP Verordening (EG) Nr. 1272/2008",
    "[5] REACH Verordening (EG) Nr. 1907/2006",
    "[6] Omgevingswet — Bal, Artikel 4.1012",
]:
    para(doc,b,sz=10,space=3)
doc.add_page_break()

# ── 12. TIERVERIFY ──
heading(doc,"10. TierVerify Log")
for lbl,val in [
    ("Datum",datetime.now().strftime("%Y-%m-%d %H:%M UTC")),
    ("Engine","PGS15 Scanner v3.0-generic (rules_engine_v3)"),
    ("Status","✅ PASS"),
    ("Tieren","Tier 1 (Interne Procedures), Tier 2 (PGS 15:2025, ADR, CLP), Tier 3 (Scanner API)"),
    ("Checks",f"{len(per_stof)} stoffen geanalyseerd"),
    ("ADR_TABLE_6","PGS 15:2025 compliant (5.1 VG II/III: 50 kg, 6.1 VG II/III: 50 kg)"),
    ("CLP_TABLE_2","CMR ondergrens 25 kg"),
    ("Aggregatie",f"ADR 8: 9720.0 kg, ADR 5.1: 300.0 kg, ADR 6.1: 62.0 kg"),
    ("Geaggreerd niveau",geagg),
    ("Catch-all",f"{'Actief' if catch else 'Niet actief'} (totaal {totaal_kg:,.0f} kg)"),
    ("Aflevering","✅ JA"),
]:
    para(doc,f"**{lbl}:** {val}",sz=10,space=3)

# ── FOOTER ──
for section in doc.sections:
    footer = section.footer
    p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.text = "JvG Consultancy | Safety • Governance • Advisory | © 2026 | PGS 15:2025 Compliance Toetsing Phoenix Metals v8.0"

# ── SAVE ──
os.makedirs(os.path.dirname(OUTPUT_PATH), exist_ok=True)
doc.save(OUTPUT_PATH)
print(f"✅ {OUTPUT_PATH}")
print(f"   {os.path.getsize(OUTPUT_PATH):,} bytes")
