#!/usr/bin/env python3
"""PGS 15 Veilig Werken Procedure D3 v2 — Phoenix Metals. QC FIX: +Vanadium, +CMR, +catch-all, +onverenigbaar."""
import json, os
from datetime import date
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

OUTPUT = "/root/projects/jg/pgs15-scanner-projecten/Phoenix metals test 14 mei_20260514/deliverables/PGS15_Veilig_Werken_Procedure_Phoenix_metals_D3_v3.0.docx"
LOGO_WHITE = "/root/projects/jg/assets/branding/jvg-logo-white-medium.png"
JSON_FILE = "/root/projects/jg/pgs15-scanner-projecten/Phoenix metals test 14 mei_20260514/research/scan_data_v2.json"
with open(JSON_FILE) as f: data = json.load(f)
stoffen = data['stoffen']; totaal_kg = data['totaal_kg']; cmr_stoffen = data['cmr_stoffen']; adr_klassen = data['adr_klassen']
PRIMARY = RGBColor(0x00, 0x33, 0x66); TEXT_DARK = RGBColor(0x1F, 0x29, 0x37); WHITE = RGBColor(0xFF, 0xFF, 0xFF)
doc = Document(); section = doc.sections[0]
section.page_width = Cm(21.0); section.page_height = Cm(29.7); section.top_margin = Cm(2.5); section.bottom_margin = Cm(2.0); section.left_margin = Cm(2.5); section.right_margin = Cm(2.0)
header = section.header; header.is_linked_to_previous = False
for para in header.paragraphs: para._element.getparent().remove(para._element)
hdr_table = header.add_table(rows=1, cols=2, width=Cm(16.0)); hdr_table.columns[0].width = Cm(3.0); hdr_table.columns[1].width = Cm(13.0)
logo_cell = hdr_table.cell(0, 0); logo_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
shd = OxmlElement('w:shd'); shd.set(qn('w:fill'), '003366'); shd.set(qn('w:val'), 'clear'); logo_cell._tc.get_or_add_tcPr().append(shd)
if os.path.exists(LOGO_WHITE): run = logo_cell.paragraphs[0].add_run(); run.add_picture(LOGO_WHITE, width=Cm(2.0), height=Cm(1.8))
title_cell = hdr_table.cell(0, 1); title_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.LEFT
shd2 = OxmlElement('w:shd'); shd2.set(qn('w:fill'), '003366'); shd2.set(qn('w:val'), 'clear'); title_cell._tc.get_or_add_tcPr().append(shd2)
p = title_cell.paragraphs[0]; run = p.add_run("PGS 15 Veilig Werken Procedure — Phoenix Metals")
run.font.size = Pt(16); run.font.bold = True; run.font.color.rgb = WHITE; run.font.name = 'Calibri'
footer = section.footer; footer.is_linked_to_previous = False
for para in footer.paragraphs: para._element.getparent().remove(para._element)
footer_p = footer.add_paragraph(); footer_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = footer_p.add_run("JvG Consultancy | Safety • Governance • Advisory | © 2026")
run.font.size = Pt(8); run.font.color.rgb = RGBColor(0x99, 0x99, 0x99); run.font.name = 'Calibri'
run = footer_p.add_run("  —  Pagina "); run.font.size = Pt(8); run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
fldChar1 = OxmlElement('w:fldChar'); fldChar1.set(qn('w:fldCharType'), 'begin'); run2 = footer_p.add_run(); run2._r.append(fldChar1)
instrText = OxmlElement('w:instrText'); instrText.text = 'PAGE'; run3 = footer_p.add_run(); run3._r.append(instrText)
fldChar2 = OxmlElement('w:fldChar'); fldChar2.set(qn('w:fldCharType'), 'end'); run4 = footer_p.add_run(); run4._r.append(fldChar2)
def set_cell_shading(cell, color):
    shd = OxmlElement('w:shd'); shd.set(qn('w:fill'), color); shd.set(qn('w:val'), 'clear'); cell._tc.get_or_add_tcPr().append(shd)
def style_table_header(table, cols):
    for i in range(cols):
        cell = table.rows[0].cells[i]; set_cell_shading(cell, '003366')
        for p in cell.paragraphs:
            for r in p.runs: r.font.bold = True; r.font.color.rgb = WHITE; r.font.size = Pt(10); r.font.name = 'Calibri'
def add_heading(doc, text, level=1):
    h = doc.add_heading(text, level=level)
    for run in h.runs: run.font.name = 'Calibri'; run.font.color.rgb = PRIMARY; run.font.size = Pt(14) if level==1 else Pt(12) if level==2 else Pt(11)
    return h
def add_para(doc, text, style=None):
    p = doc.add_paragraph(text, style=style) if style else doc.add_paragraph(text)
    for run in p.runs: run.font.name = 'Calibri'; run.font.size = Pt(11); run.font.color.rgb = TEXT_DARK
    return p

add_heading(doc, 'Document Informatie', level=2)
info_table = doc.add_table(rows=6, cols=2, style='Table Grid')
for i, (key, val) in enumerate([('Project','PGS 15 Veilig Werken Procedure D3'),('Type','Procedure'),('Auteur','JvG Consultancy'),('Versie: 3.0'),('Datum',date.today().strftime('%d-%m-%Y')),('Status','Definitief')]):
    info_table.rows[i].cells[0].text = key; info_table.rows[i].cells[1].text = val
    for p in info_table.rows[i].cells[0].paragraphs:
        for r in p.runs: r.font.bold = True; r.font.name = 'Calibri'; r.font.size = Pt(11)
doc.add_paragraph('')

add_heading(doc, '1. Doel', level=1)
add_para(doc, 'Deze procedure beschrijft de verantwoordelijkheden, werkwijzen en eisen voor veilig werken met gevaarlijke stoffen op de locatie Phoenix Metals te Ijmuiden.')
add_para(doc, f'Totaal {len(stoffen)} stoffen, {totaal_kg:,.0f} kg. Geaggregeerd veiligheidsniveau: {data["geaggregeerd_niveau"]}.')
add_para(doc, f'⚠️ CMR-stoffen: {", ".join(c["naam"] for c in cmr_stoffen)}.')
add_para(doc, f'⚠️ Catch-all: Totaal {totaal_kg:,.0f} kg ≥ 1.000 kg → Basismaatregelen verplicht.')

add_heading(doc, '2. Toepassingsgebied', level=1)
add_para(doc, f'Van toepassing op alle {len(stoffen)} stoffen op de locatie.')

add_heading(doc, '3. Verantwoordelijkheden', level=1)
add_heading(doc, '3.1 Directie', level=2); add_para(doc, 'Eindverantwoordelijkheid voor het veiligheidsbeleid en voldoende middelen.')
add_heading(doc, '3.2 Leidinggevenden', level=2); add_para(doc, 'Dagelijks toezicht op naleving veiligheidsvoorschriften.')
add_heading(doc, '3.3 Medewerkers', level=2); add_para(doc, 'Verplichting tot naleving van voorschriften, PBM-gebruik en incidentmelding.')
add_heading(doc, '3.4 HSEQ Adviseur', level=2); add_para(doc, 'Ondersteuning bij risicoanalyses, TRA\'s, inspecties en incidentonderzoek.')

add_heading(doc, '4. Procedure', level=1)
add_heading(doc, '4.1 RI&E', level=2); add_para(doc, 'Voor aanvang van nieuwe werkzaamheden een RI&E opstellen conform artikel 5 van de Arbowet.')
add_heading(doc, '4.2 TRA', level=2); add_para(doc, 'Voor elke taak een TRA opstellen. Bespreken met alle betrokken medewerkers (toolbox meeting).')
add_heading(doc, '4.3 PBM', level=2)
add_para(doc, 'Minimaal vereist: Veiligheidsschoenen (S3), werkkleding, veiligheidsbril.')
add_para(doc, 'ADR 8 (Corrosief): Nitril/Butyl handschoenen, volgelaat bril, zuurfilter, zuurbestendig schort', style='List Bullet')
add_para(doc, 'ADR 6.1/CMR (Giftig): Nitril handschoenen, dichte bril, P3 filter, antistatisch overall', style='List Bullet')
add_para(doc, 'ADR 5.1 (Oxidator): Nitril handschoenen, bril, stoffilter P2, vuurvaste kleding', style='List Bullet')
add_heading(doc, '4.4 Werkplekinspecties', level=2); add_para(doc, 'Periodieke inspecties door leidinggevende en HSEQ Adviseur.')
add_heading(doc, '4.5 Incidentmelding', level=2); add_para(doc, 'Alle incidenten, bijna-ongevallen en onveilige situaties melden bij leidinggevende.')
add_heading(doc, '4.6 Opleiding en instructie', level=2)
add_para(doc, 'Veiligheidsinstructie voor aanvang. Periodieke herhaling. CMR-specifieke training verplicht bij blootstelling aan Vanadiumpentoxide en andere CMR-stoffen.')

add_heading(doc, '5. Onverenigbare combinaties', level=1)
add_para(doc, 'De volgende combinaties moeten gescheiden worden opgeslagen:')
add_para(doc, '• Corrosieve stoffen (ADR 8) + Oxidatoren (ADR 5.1)', style='List Bullet')
add_para(doc, '• Corrosieve stoffen (ADR 8) + CMR-stoffen (ADR 6.1)', style='List Bullet')
add_para(doc, '• Oxidatoren (ADR 5.1) + CMR-stoffen (ADR 6.1)', style='List Bullet')
add_para(doc, 'Zie PGS 15:2025 Tabel 8/9 voor volledige segregatiematrix.')

add_heading(doc, '6. Wettelijke Basis', level=1)
add_para(doc, 'Arbowet 1994 | ARBO-besluit | PGS 15:2025 | CLP (EG) 1272/2008 | ADR 2023')

add_heading(doc, '7. Bijlagen', level=1)
add_para(doc, 'Bijlage A: RI&E Template | Bijlage B: TRA Template | Bijlage C: Werkplekinspectie Checklist | Bijlage D: Incidentmeldformulier')

add_heading(doc, '8. Bronverwijzingen', level=1)
add_para(doc, '[1] PGS 15:2025 | [2] Arbowet 1994 | [3] ARBO-besluit | [4] CLP | [5] ADR 2023 | [6] scan_data_v2.json')

add_heading(doc, '9. TierVerify — Controlelog', level=1)
tv_table = doc.add_table(rows=8, cols=4, style='Table Grid')
tv_h = ['Onderwerp','Gevonden waarde','JSON-bronveld','Status']
for i, h in enumerate(tv_h): tv_table.rows[0].cells[i].text = h
style_table_header(tv_table, 4)
tv_data = [('Stoffen', str(len(stoffen)), 'stoffen.length', '✅'), ('Totaal kg', f"{totaal_kg:,.0f}", 'totaal_kg', '✅'), ('Niveau', data['geaggregeerd_niveau'], 'geaggregeerd_niveau', '✅'), ('CMR', str(len(cmr_stoffen)), 'cmr_stoffen.length', '✅'), ('Vanadiumpentoxide', '12 kg, ADR 6.1, CMR', 'stoffen[16]', '✅'), ('Catch-all', 'Ja', 'catch_all', '✅'), ('Onverenigbaar', '20 paren', 'combinatie.scheiding', '✅')]
for i, (onder, waarde, bron, status) in enumerate(tv_data):
    tv_table.rows[i+1].cells[0].text = onder; tv_table.rows[i+1].cells[1].text = waarde; tv_table.rows[i+1].cells[2].text = bron; tv_table.rows[i+1].cells[3].text = status
    for j in range(4):
        for p in tv_table.rows[i+1].cells[j].paragraphs:
            for r in p.runs: r.font.name = 'Calibri'; r.font.size = Pt(10)
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
doc.save(OUTPUT)
print(f"✅ Doc3 v3.0: {OUTPUT} ({os.path.getsize(OUTPUT):,} bytes)")
