#!/usr/bin/env python3
"""Genereer PGS-15 Beleidsdocument Policy v1.0 — Phoenix Metals IJmuiden"""

from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml
import os

OUT = "/root/projects/jg/2026-pgs15-phoenix-metals/deliverables/docx/PGS15_Beleidsdocument_Policy_v1.0.docx"
LOGO = "/root/projects/jg/2026-pgs15-phoenix-metals/assets/branding/jvg-consultancy-logo.jpg"
PRIMARY = RGBColor(0x00, 0x33, 0x66)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK_TEXT = RGBColor(0x1F, 0x29, 0x37)

doc = Document()

# ---- Default font ----
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(11)
font.color.rgb = DARK_TEXT
style.paragraph_format.space_after = Pt(6)
style.paragraph_format.line_spacing = 1.15

# ---- Helper functions ----
def set_cell_shading(cell, color_hex):
    shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="{color_hex}"/>')
    cell._tc.get_or_add_tcPr().append(shading)

def add_header_row(table, texts):
    row = table.rows[0]
    for i, txt in enumerate(texts):
        cell = row.cells[i]
        cell.text = ""
        p = cell.paragraphs[0]
        run = p.add_run(txt)
        run.bold = True
        run.font.color.rgb = WHITE
        run.font.size = Pt(10)
        run.font.name = 'Calibri'
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        set_cell_shading(cell, "003366")

def add_row(table, texts, bold_first=False):
    row = table.add_row()
    for i, txt in enumerate(texts):
        cell = row.cells[i]
        cell.text = ""
        p = cell.paragraphs[0]
        run = p.add_run(txt)
        run.font.size = Pt(10)
        run.font.name = 'Calibri'
        if i == 0 and bold_first:
            run.bold = True

def set_table_borders(table):
    tbl = table._tbl
    tblPr = tbl.tblPr if tbl.tblPr is not None else parse_xml(f'<w:tblPr {nsdecls("w")}/>')
    borders = parse_xml(
        f'<w:tblBorders {nsdecls("w")}>'
        '<w:top w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '<w:left w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '<w:bottom w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '<w:right w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '<w:insideH w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '<w:insideV w:val="single" w:sz="4" w:space="0" w:color="E5E7EB"/>'
        '</w:tblBorders>'
    )
    tblPr.append(borders)

def add_heading(text, level=1):
    h = doc.add_heading(text, level=level)
    for run in h.runs:
        run.font.name = 'Calibri'
        run.font.color.rgb = PRIMARY
    return h

def add_para(text, bold=False):
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.name = 'Calibri'
    run.font.size = Pt(11)
    run.bold = bold
    return p

def add_bullet(text, level=0):
    p = doc.add_paragraph(text, style='List Bullet')
    for run in p.runs:
        run.font.name = 'Calibri'
        run.font.size = Pt(11)
    if level > 0:
        p.paragraph_format.left_indent = Cm(1.5 * level)
    return p

# ---- Sections setup ----
section = doc.sections[0]
section.page_width = Cm(21)
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.5)

# ---- Headers & Footers ----
header = section.header
header.is_linked_to_previous = False
hp = header.paragraphs[0]
hp.alignment = WD_ALIGN_PARAGRAPH.RIGHT
run = hp.add_run("JvG Consultancy | PGS-15 Beleidsdocument")
run.font.name = 'Calibri'
run.font.size = Pt(9)
run.font.color.rgb = RGBColor(0x6B, 0x72, 0x80)

footer = section.footer
footer.is_linked_to_previous = False
fp = footer.paragraphs[0]
fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = fp.add_run("© 2026 JvG Consultancy | HSEQ | 26 april 2026 | Vertrouwelijk")
run.font.name = 'Calibri'
run.font.size = Pt(8)
run.font.color.rgb = RGBColor(0x6B, 0x72, 0x80)

# ============================================================
# VOORBLAD
# ============================================================
doc.add_paragraph()  # spacer

# Logo
if os.path.exists(LOGO):
    doc.add_picture(LOGO, width=Inches(2.2))
    last = doc.paragraphs[-1]
    last.alignment = WD_ALIGN_PARAGRAPH.CENTER

doc.add_paragraph()

p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run("PGS-15 OPSLAGVEILIGHEID BELEID")
run.bold = True
run.font.size = Pt(28)
run.font.color.rgb = PRIMARY
run.font.name = 'Calibri'

p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run("Phoenix Metals IJmuiden")
run.font.size = Pt(18)
run.font.color.rgb = PRIMARY
run.font.name = 'Calibri'

p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run("Beleidsdocument — Versie 1.0")
run.font.size = Pt(14)
run.font.color.rgb = DARK_TEXT
run.font.name = 'Calibri'

doc.add_paragraph()

# Meta-data tabel
t = doc.add_table(rows=1, cols=2)
t.alignment = WD_TABLE_ALIGNMENT.CENTER
set_table_borders(t)
meta = [
    ("Documenttitel", "PGS-15 Opslagveiligheid Beleid"),
    ("Organisatie", "Phoenix Metals IJmuiden"),
    ("Versie", "1.0"),
    ("Datum", "26 april 2026"),
    ("Status", "Definitief"),
    ("Classificatie", "Vertrouwelijk"),
    ("PGS-referentie", "PGS 15:2025 v1.0"),
    ("Auteur", "JvG Consultancy — HSEQ Divisie"),
]
add_header_row(t, ["Parameter", "Waarde"])
for r in meta:
    add_row(t, list(r), bold_first=True)

doc.add_paragraph()

# Goedkeuringstabel
t2 = doc.add_table(rows=1, cols=4)
t2.alignment = WD_TABLE_ALIGNMENT.CENTER
set_table_borders(t2)
add_header_row(t2, ["Rol", "Naam", "Functie", "Handtekening / Datum"])
approval = [
    ("Opsteller", "J. van Gemert", "HSEQ Consultant", ""),
    ("Controller", "Vrijgehouden", "Kwaliteitsmanager", ""),
    ("Goedkeurer", "Vrijgehouden", "Directie Phoenix Metals", ""),
]
for r in approval:
    add_row(t2, list(r), bold_first=True)

doc.add_paragraph()

# Vertrouwelijkheidsclausule
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run("VERTROUWELIJKHEIDSCLAUSULE")
run.bold = True
run.font.size = Pt(11)
run.font.name = 'Calibri'
run.font.color.rgb = PRIMARY

add_para(
    "Dit document is eigendom van JvG Consultancy en Phoenix Metals IJmuiden. "
    "Het is uitsluitend bestemd voor geautoriseerde medewerkers en derden die "
    "betrokken zijn bij de opslag van gevaarlijke stoffen op de locatie IJmuiden. "
    "Kopiëren, distribueren of openbaar maken zonder schriftelijke toestemming van "
    "de directie van Phoenix Metals is verboden. Overtreding hiervan kan leiden tot "
    "juridische stappen op grond van de Algemene Verordening Gegevensbescherming "
    "en de Wet op de Ondernemingsraden."
)

doc.add_page_break()

# ============================================================
# INHOUDSOPGAVE (placeholder — python-docx heeft geen TOC-veld, we voegen een paginabreak toe)
# ============================================================
add_heading("Inhoudsopgave", level=1)
add_para(
    "Opmerking: de inhoudsopgave wordt automatisch bijgewerkt na openen in Microsoft Word. "
    "Klik met de rechtermuisknop op dit veld en selecteer 'Veld bijwerken' om de paginanummers te verversen."
)
# Add TOC field
p = doc.add_paragraph()
run = p.add_run()
fldChar1 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
run._r.append(fldChar1)
run2 = p.add_run()
instrText = parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> TOC \\o "1-3" \\h \\z \\u </w:instrText>')
run2._r.append(instrText)
run3 = p.add_run()
fldChar2 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="separate"/>')
run3._r.append(fldChar2)
run4 = p.add_run("[Inhoudsopgave — bijwerken in Word]")
run4.font.color.rgb = RGBColor(0x80, 0x80, 0x80)
run4.font.name = 'Calibri'
run5 = p.add_run()
fldChar3 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
run5._r.append(fldChar3)

doc.add_page_break()

# ============================================================
# 1. DOEL EN REIKWIJDTE
# ============================================================
add_heading("1. Doel en Reikwijdte", level=1)

add_para(
    "Dit beleidsdocument definieert het kader voor de veilige opslag van verpakte gevaarlijke "
    "stoffen bij Phoenix Metals IJmuiden, conform de eisen van Publicatiereeks Gevaarlijke "
    "Stoffen 15:2025 (PGS 15:2025). Het document dient als toetssteen voor alle operationele, "
    "tactische en strategische besluitvorming rondom stofopslag."
)

add_para(
    "De aanleiding voor dit beleid is de vastgestelde noodzaak om de opslagpraktijken van "
    "Phoenix Metals te toetsen aan de actuele PGS 15:2025 richtlijn. Uit de nulmeting is "
    "gebleken dat de huidige opslag van circa 300 liter ADR-klasse 8 stoffen (natriumhydroxide "
    "en zwavelzuur in diverse concentraties) niet volledig voldoet aan de scheidingseisen uit "
    "Bijlage E, Tabel 9 van PGS 15:2025. Dit beleid adresseert die lacune en stelt het kader "
    "op voor structurele compliance."
)

add_heading("1.1 Geldigheidsgebied", level=2)
add_para(
    "Dit beleid is van toepassing op alle opslaglocaties van Phoenix Metals op de vestiging "
    "IJmuiden. Dit omvat de primaire opslagvoorziening (storage racking — rack in front of lab) "
    "en eventuele toekomstige opslaglocaties die binnen hetzelfde brandcompartiment vallen. "
    "Het beleid geldt onverkort voor alle activiteiten die verband houden met de opslag, "
    "inclusief ontvangst, interne transport, etikettering, en afvoer van gevaarlijke stoffen."
)

add_heading("1.2 Doelgroep", level=2)
add_para(
    "Dit beleid richt zich tot alle personen die werkzaam zijn op of toegang hebben tot de "
    "opslaglocaties van Phoenix Metals, inclusief:"
)
add_bullet("Vaste medewerkers van Phoenix Metals")
add_bullet("Tijdelijke medewerkers en uitzendkrachten")
add_bullet("Aannemers en onderhoudspersoneel")
add_bullet("Bezoekers en derden die toegang hebben tot opslagruimten")
add_bullet("Stagiaires en leerlingen")

add_para(
    "Iedereen die zich op de opslaglocatie bevindt, wordt geacht kennis te hebben genomen van "
    "dit beleid en dienovereenkomstig te handelen. Onbekendheid met het beleid ontslaat niet "
    "van de verplichting tot naleving."
)

# ============================================================
# 2. BELEIDSVERKLARING
# ============================================================
add_heading("2. Beleidsverklaring", level=1)

p = doc.add_paragraph()
run = p.add_run(
    '"Phoenix Metals streeft naar 100% compliance met PGS 15:2025 voor de opslag van '
    'verpakte gevaarlijke stoffen op alle locaties."'
)
run.bold = True
run.italic = True
run.font.size = Pt(12)
run.font.color.rgb = PRIMARY
run.font.name = 'Calibri'
p.alignment = WD_ALIGN_PARAGRAPH.CENTER

add_para(
    "De directie van Phoenix Metals committeert zich aan het veilig opslaan van gevaarlijke "
    "stoffen conform de geldende wet- en regelgeving. Dit commitment omvat het beschikbaar "
    "stellen van voldoende financiële en menselijke middelen om de in dit beleid vervatte "
    "maatregelen te implementeren en te handhaven."
)

add_para(
    "Phoenix Metals hanteert een zero-tolerance beleid ten aanzien van niet-compliance met "
    "de opslagvoorschriften. Overtredingen worden direct geadresseerd conform de in "
    "hoofdstuk 10 omschreven handhavingprocedure. Herhaalde of ernstige overtredingen "
    "kunnen leiden tot disciplinaire maatregelen, waaronder ontzegging van toegang tot de "
    "opslagfaciliteit."
)

add_para(
    "De directie stelt zich proactief op: nieuwe wetgeving, gewijzigde inzichten of "
    "aanpassingen in het chemisch register leiden tot directe herbeoordeling van dit beleid. "
    "Het beleid wordt minimaal jaarlijks geëvalueerd en waar nodig herzien."
)

# ============================================================
# 3. WETTELIJK KADER
# ============================================================
add_heading("3. Wettelijk Kader", level=1)

add_para(
    "De opslag van gevaarlijke stoffen in Nederland valt onder een gelaagd juridisch kader. "
    "De primaire richtlijn voor de opslag van verpakte gevaarlijke stoffen is PGS 15:2025. "
    "Deze publicatie is het resultaat van samenwerking tussen overheid, bedrijfsleven en "
    "kennisinstellingen en fungeert als de branchestandaard voor opslagveiligheid. PGS 15:2025 "
    "vervangt de eerdere versies en bevat verregaande verplichtingen op het gebied van "
    "stofscheiding, vloeistofopvang, brandpreventie en deskundigheids Eisen."
)

add_heading("3.1 Omgevingswet", level=2)
add_para(
    "De Omgevingswet (inwerking getreden 1 januari 2024) integreert het Besluit bouw- en "
    "sloopwerken in het buitenland (Bbl), het Besluit kwaliteit leefomgeving (Bkl) en de "
    "Besluit activiteiten leefomgeving (Bal). Voor Phoenix Metals is met name het Bkl relevant "
    "vanwege de eisen aan brandcompartimentering en externe veiligheidsafstanden. Het Bbl "
    "stelt constructieve eisen aan de opslagvoorziening, waaronder de brandwerendheid van "
    "scheidingswanden en de draagconstructie."
)

add_heading("3.2 Arbowet", level=2)
add_para(
    "De Arbeidsomstandighedenwet (Arbowet) legt een algemene zorgplicht op de werkgever "
    "om veilige arbeidsomstandigheden te waarborgen. Artikel 4.1c van het Arbobesluit "
    "verplicht de werkgever tot het uitvoeren van een Risico-Inventarisatie en -Evaluatie "
    "(RI&E) die expliciet de opslag en het gebruik van gevaarlijke stoffen meeneemt. De "
    "RI&E vormt de basis voor de in hoofdstuk 7 beschreven risicobeheersmaatregelen."
)

add_heading("3.3 ADR", level=2)
add_para(
    "Het Accord européen relatif au transport international des marchandises Dangereuses "
    "par Route (ADR) classificeert gevaarlijke stoffen voor vervoer over de weg. Hoewel ADR "
    "primair gericht is op transport, vormen de ADR-klassen en verpakkingsgroepen (PG I, II, "
    "III) de basis voor de classificatie in PGS 15:2025. Phoenix Metals hanteert uitsluitend "
    "ADR-klasse 8 (bijtende stoffen) met verpakkingsgroep II."
)

add_heading("3.4 CLP en REACH", level=2)
add_para(
    "De CLP-Verordening (EG 1272/2008) harmoniseert de classificatie, etikettering en "
    "verpakking van stoffen en mengsels binnen de EU. REACH (EG 1907/2006) regelt de "
    "registratie, evaluatie en autorisatie van chemische stoffen. Voor Phoenix Metals is "
    "REACH met name relevant vanwege de verplichting om Safety Data Sheets (SDS / VIB) "
    "beschikbaar te stellen aan medewerkers. De SDS bevat de essentiële informatie voor "
    "veilige omgang en opslag."
)

add_heading("3.5 Relatie tussen wetgevingen", level=2)
t = doc.add_table(rows=1, cols=4)
set_table_borders(t)
add_header_row(t, ["Wetgeving", "Bereik", "Relevantie PM", "Overlap met PGS 15"])
laws = [
    ("PGS 15:2025", "Opslag verpakte gevaarlijke stoffen", "Primaire richtlijn", "—"),
    ("Omgevingswet (Bbl/Bkl)", "Bouwtechnische eisen, milieu", "Brandcompartimentering, afstanden", "M15, M109"),
    ("Arbowet / Arbobesluit", "Arbeidsomstandigheden", "RI&E, zorgplicht", "MW1, M85, M86"),
    ("ADR", "Transportclassificatie", "Klasse 8 PG II → opslagklasse", "Tabel 6, Tabel 7"),
    ("CLP (EG 1272/2008)", "Etikettering, classificatie", "H-zinnen, etiketten", "M36, M45"),
    ("REACH (EG 1907/2006)", "Registratie, SDS", "VIB/SDS beschikbaarheid", "M85"),
]
for r in laws:
    add_row(t, list(r), bold_first=True)

add_para("[1] PGS 15:2025, Publicatiereeks Gevaarlijke Stoffen, versie 1.0")
add_para("[2] Omgevingswet, Besluit kwaliteit leefomgeving (Bkl), art. 4.12-4.18")

# ============================================================
# 4. DEFINITIES EN AFKORTINGEN
# ============================================================
add_heading("4. Definities en Afkortingen", level=1)

add_para(
    "Onderstaande tabel definieert de in dit document gebruikte termen en afkortingen. "
    "De definitie sluit aan bij het taalgebruik in PGS 15:2025 en de relevante wetgeving."
)

t = doc.add_table(rows=1, cols=3)
set_table_borders(t)
add_header_row(t, ["Term / Afkorting", "Betekenis", "Context"])
defs = [
    ("PGS", "Publicatiereeks Gevaarlijke Stoffen", "Branchestandaard opslag gevaarlijke stoffen"),
    ("ADR", "Accord européen… Dangereuses par Route", "Europees verdrag transport gevaarlijke stoffen"),
    ("SDS / VIB", "Safety Data Sheet / Veiligheidsinformatieblad", "Document met veiligheidsinfo per stof"),
    ("PBM", "Persoonlijke Beschermingsmiddelen", "Handschoenen, brillen, schorten, etc."),
    ("VBB", "Verpakt Blusmiddelen Bedrijf", "Semi-automatische blusinstallatie"),
    ("UPD", "Uitbreidings- en Preventiedienst", "Brandweerpreventieorganisatie"),
    ("Wbdbo", "Weerstand tegen branddoorbraak en -overslag", "Brandwerendheidsmaat in minuten"),
    ("RI&E", "Risico-Inventarisatie en -Evaluatie", "Verplichte risicobeoordeling Arbowet"),
    ("CLP", "Classification, Labelling, Packaging", "EU-verordening stofclassificatie"),
    ("REACH", "Registration, Evaluation, Authorisation of Chemicals", "EU-verordening chemische stoffen"),
    ("MW1", "Maatregel Werkvoorraad 1 — Zorgplicht", "Basisverplichting PGS 15"),
    ("M2", "Maatregel 2 — Bestemde opslag", "Opslag in daartoe bestemde voorziening"),
    ("M30", "Maatregel 30 — Vloeistofopvang", "Lekbakken / opvangvoorzieningen"),
    ("M35", "Maatregel 35 — Stoffenscheiding", "Scheiding onverenigbare stoffen"),
    ("M109", "Maatregel 109 — Hulpdiensten", "Toegankelijkheid voor brandweer"),
    ("CAS", "Chemical Abstracts Service", "Uniek stofidentificatienummer"),
    ("PG", "Packaging Group (I, II, III)", "Verpakkingsgroep naar gevaarzwaarte"),
]
for d in defs:
    add_row(t, list(d), bold_first=True)

# ============================================================
# 5. VERANTWOORDELIJKHEDEN
# ============================================================
add_heading("5. Verantwoordelijkheden", level=1)

add_para(
    "De verantwoordelijkheden voor het waarborgen van veilige opslag zijn verdeeld over "
    "meerdere functies. Onderstaande RACI-matrix (Responsible, Accountable, Consulted, "
    "Informed) definieert de rollen en bevoegdheden per taakgebied."
)

# RACI tabel
t = doc.add_table(rows=1, cols=7)
set_table_borders(t)
add_header_row(t, ["Taakgebied", "Directie", "HSEQ Manager", "Lab Manager", "Medewerkers", "Aannemers", "UPD/Brandweer"])
raci = [
    ("Beleid opstellen en goedkeuren", "A", "R", "C", "I", "I", "I"),
    ("Chemisch register beheren", "I", "A", "R", "C", "I", "I"),
    ("Stoffenscheiding handhaven", "I", "A", "R", "R", "R", "I"),
    ("SDS/VIB beschikbaar stellen", "I", "A", "R", "I", "I", "I"),
    ("Opleiding en instructie geven", "I", "A", "R", "C", "I", "I"),
    ("Interne audits uitvoeren", "I", "R/A", "C", "I", "I", "C"),
    ("Inspecties uitvoeren", "I", "C", "A", "R", "I", "I"),
    ("Noodplan onderhouden", "A", "R", "C", "I", "I", "C"),
    ("Calamiteiten afhandelen", "A", "R", "R", "R", "R", "R"),
    ("Risico-inventarisatie (RI&E)", "A", "R", "C", "C", "I", "C"),
    ("Documentbeheer beleid", "A", "R", "C", "I", "I", "I"),
]
for r in raci:
    add_row(t, list(r), bold_first=True)

add_para("R = Responsible (uitvoerend) | A = Accountable (eindverantwoordelijk) | C = Consulted (gevraagd advies) | I = Informed (wordt geïnformeerd)")

add_heading("5.1 Directie", level=2)
add_para(
    "De directie draagt de eindverantwoordelijkheid (Accountable) voor de implementatie en "
    "handhaving van dit beleid. De directie stelt de benodigde middelen beschikbaar, "
    "goedkeurt het beleid en de bijbehorende procedures, en zorgt ervoor dat de HSEQ Manager "
    "de bevoegdheid heeft om handhavend op te treden bij niet-compliance. De directie ontvangt "
    "minimaal viermaal per jaar een rapportage over de compliancestatus."
)

add_heading("5.2 HSEQ Manager", level=2)
add_para(
    "De HSEQ Manager is verantwoordelijk voor de dagelijkse implementatie en handhaving van "
    "dit beleid. Dit omvat het beheren van het chemisch register, het uitvoeren van interne "
    "audits, het coordineren van opleiding en instructie, en het fungeren als primaire "
    "contactpersoon voor de UPD en andere toezichthouders. De HSEQ Manager heeft de bevoegdheid "
    "om de opslag te sluiten bij acuut gevaar en om medewerkers de toegang te ontzeggen bij "
    "structurele niet-compliance."
)

add_heading("5.3 Lab Manager", level=2)
add_para(
    "De Lab Manager is verantwoordelijk voor de fysieke inrichting van de opslaglocatie, "
    "inclusief de plaatsing van lekbakken, vakmarkeringen en etikettering. De Lab Manager "
    "zorgt ervoor dat de stoffenscheiding conform Bijlage E, Tabel 9 van PGS 15:2025 "
    "wordt gehandhaafd en rapporteert afwijkingen direct aan de HSEQ Manager."
)

add_heading("5.4 Medewerkers", level=2)
add_para(
    "Alle medewerkers zijn verplicht om dit beleid na te leven. Dit omvat het correct "
    "opslaan van stoffen op de daartoe bestemde locaties, het melden van lekkages of "
    "andere incidenten, en het dragen van de voorgeschreven persoonlijke "
    "beschermingsmiddelen. Medewerkers ontvangen jaarlijks instructie over de opslagregels "
    "en de bijbehorende risico's."
)

add_heading("5.5 Aannemers", level=2)
add_para(
    "Aannemers die werkzaamheden uitvoeren op de opslaglocatie ontvangen een specifieke "
    "instructie vóór aanvang van de werkzaamheden. Deze instructie omvat de locatie van "
    "opgeslagen stoffen, de geldende veiligheidsregels en de procedure bij calamiteiten. "
    "Aannemers werken uitsluitend onder toezicht van een daartoe bevoegde medewerker van "
    "Phoenix Metals."
)

# ============================================================
# 6. OPSLAGPRINCIPES
# ============================================================
add_heading("6. Opslagprincipes", level=1)

add_heading("6.1 Algemene beginselen", level=2)
add_para(
    "PGS 15:2025 hanteert twee fundamentele beginselen voor de opslag van gevaarlijke stoffen. "
    "Het eerste beginsel is de zorgplicht (MW1): degene die gevaarlijke stoffen opslaat, is "
    "verplicht om aantoonbaar voldoende maatregelen te treffen om mens en milieu te beschermen. "
    "Dit is geen formuleerbare norm, maar een dynamische verplichting die meegroeit met de "
    "inzichten en omstandigheden. De zorgplicht geldt onverkort, ongeacht het opgeslagen volume."
)
add_para(
    "Het tweede beginsel is de bestemde opslag (M2): gevaarlijke stoffen mogen uitsluitend "
    "worden opgeslagen in voorzieningen die daartoe zijn ontworpen, gebouwd en ingericht. "
    "Dit betekent dat opslag in werkgangen, vluchtroutes of gedeelde ruimten zonder adequate "
    "voorzieningen niet is toegestaan. Voor Phoenix Metals betekent dit dat het storage racking "
    "voor het lab moet voldoen aan de constructieve en veiligheidstechnische eisen uit PGS 15:2025."
)

add_heading("6.2 Veiligheidsniveaus", level=2)
add_para(
    "PGS 15:2025 kent opslaglocaties toe aan veiligheidsniveaus op basis van de opgeslagen "
    "hoeveelheden per ADR-klasse (Tabel 6). Voor Phoenix Metals geldt het basisveiligheidsniveau, "
    "aangezien het totale volume ADR-klasse 8 stoffen circa 300 liter (~390 kg) bedraagt, "
    "hetgeen ver onder de ondergrens van 2.500 kg (Tabel 7) ligt."
)
t = doc.add_table(rows=1, cols=4)
set_table_borders(t)
add_header_row(t, ["Niveau", "Volume ADR 8", "Wbdbo-eis", "Aanvullende eisen"])
levels = [
    ("Basis", "< 10.000 kg", "Bbl (geen specifieke Wbdbo)", "Lekbakken, scheiding, ventilatie"),
    ("VN-B (60 min)", "10.000 – 20.000 kg", "60 min Wbdbo", "Blusinstallatie, detectie, D6/D10/D11"),
    ("VN-A (D12)", "> 20.000 kg", "60-90 min Wbdbo", "VBB-installatie, PAC-doormelding"),
    ("Phoenix Metals", "~390 kg", "Basis (Bbl)", "Lekbakken + stoffenscheiding"),
]
for r in levels:
    add_row(t, list(r), bold_first=True)

add_heading("6.3 Stoffenscheiding", level=2)
add_para(
    "De scheiding van onverenigbare stoffen is een kerneis van PGS 15:2025, onafhankelijk "
    "van het veiligheidsniveau. Bijlage E, Tabel 9 definieert drie scheiding niveaus:"
)
add_bullet("A: Apart brandcompartiment of 5 m vrije zone — strengste scheiding")
add_bullet("B: Beoordeling vereist — gescheiden opslag tenzij VIB aantoont dat stoffen niet reageren")
add_bullet("V: Aparte vakken binnen hetzelfde brandcompartiment")

add_para(
    "Voor Phoenix Metals is de kritieke bevinding dat natriumhydroxide (NaOH, base) en "
    "zwavelzuur (H₂SO₄, zuur) een A-scheiding vereisen. Beide stoffen vallen onder ADR-klasse 8, "
    "maar hun chemische onverenigheid (exotherme neutralisatiereactie) maakt aparte opslag "
    "verplicht. Daarnaast vereist calcium oxide (sterk basisch) een A-scheiding ten opzichte "
    "van zwavelzuur."
)

t = doc.add_table(rows=1, cols=4)
set_table_borders(t)
add_header_row(t, ["Stofcombinatie", "Scheiding", "Niveau", "Toelichting"])
sep = [
    ("NaOH 50% ↔ H₂SO₄ (alle)", "Ja", "A", "Zuur + base, exotherme reactie"),
    ("NaOH 50% ↔ Aluminiumsulfaat", "Ja", "B", "Base + zout, VIB-consultatie nodig"),
    ("NaOH 50% ↔ Calciumoxide", "Ja", "B", "Base + basisch oxide, beoordeling"),
    ("H₂SO₄ ↔ H₂SO₄ (andere conc.)", "Nee", "—", "Zelfde stof, zelfde klasse"),
    ("H₂SO₄ ↔ Calciumoxide", "Ja", "A", "Zuur + base, exotherm risico"),
    ("H₂SO₄ ↔ Aluminiumsulfaat", "Beoordelen", "B", "Zuur + zout, potentiële reactie"),
]
for r in sep:
    add_row(t, list(r), bold_first=True)

add_para(
    "De voorgestelde oplossing conform de E.3-uitzondering (opslag < 10.000 kg): NaOH en H₂SO₄ "
    "in aparte lekbakken met gemarkeerde vakken en minimaal 2 m afstand. Calciumoxide apart "
    "van alle zwavelzuurproducten."
)

add_heading("6.4 Vloeistofopvang", level=2)
add_para(
    "Maatregel 30 (M30) vereist dat alle vloeibare gevaarlijke stoffen worden opgeslagen in "
    "of boven een opvangvoorziening die geschikt is om lekkende of gemorste vloeistof op te "
    "vangen. De capaciteit van de opvangvoorziening moet minimaal 110% bedragen van het volume "
    "van de grootste enkele verpakking in de betreffende opslag. Voor Phoenix Metals betekent "
    "dit lekbakken met een minimale capaciteit van 27,5 liter (110% van 25 liter jerrycan)."
)
add_para(
    "De lekbakken moeten chemisch bestand zijn tegen de opgeslagen stoffen. Voor ADR-klasse 8 "
    "(bijtend) zijn polyethyleen (PE) lekbakken geschikt. De lekbakken worden geplaatst op een "
    "vlakke, niet-poreuze ondergrond en zijn voorzien van een afvoervoorziening of worden "
    "periodiek gecontroleerd op vochtophoping."
)

add_heading("6.5 Maximale hoeveelheden", level=2)
add_para(
    "Maatregel 15 (M15) bepaalt de maximale oppervlakte van een brandcompartiment. Voor het "
    "basisveiligheidsniveau bedraagt de maximale oppervlakte 1.000 m² bij opslag < 20.000 kg "
    "en 2.500 m² bij opslag > 20.000 kg. Phoenix Metals bevindt zich met circa 390 kg ruim "
    "binnen de eerste categorie. De maximale oppervlakte van het huidige brandcompartiment "
    "dient te worden vastgesteld en gedocumenteerd."
)
add_para(
    "Daarnaast geldt de werkvoorraadregeling (M14): de hoeveelheid gevaarlijke stoffen die "
    "buiten de opslagvoorziening aanwezig mag zijn, is beperkt tot wat direct nodig is voor "
    "de lopende werkzaamheden. Aangebroken verpakkingen worden direct na gebruik teruggeplaatst "
    "in de opslagvoorziening."
)

# ============================================================
# 7. RISICOBEHEERSING
# ============================================================
add_heading("7. Risicobeheersing", level=1)

add_para(
    "De risicobeheersing is gebaseerd op de RI&E en de specifieke kenmerken van de bij "
    "Phoenix Metals opgeslagen stoffen. De risicomatrix kent een waarschijnlijkheidsniveau "
    "(1 = onwaarschijnlijk tot 5 = frequent) toe aan een effectniveau (1 = verwaarloosbaar "
    "tot 5 = catastrofaal). Het risiconiveau is het product van beide."
)

add_heading("7.1 Top-3 risico's", level=2)

add_heading("7.1.1 Risico 1: Menging NaOH en H₂SO₄", level=3)
t = doc.add_table(rows=1, cols=3)
set_table_borders(t)
add_header_row(t, ["Aspect", "Preventief", "Repressief"])
add_row(t, ["Maatregel", "A-scheiding conform Tabel 9\nAparte lekbakken\n2 m afstand\nVakmarkering", "Nooddouche + oogdouche binnen 10 m\nInstructiekaart bij rack\nCalamiteitenplan activeren"])
add_row(t, ["Waarschijnlijkheid", "2 (Soms — bij falen scheiding)", "—"])
add_row(t, ["Effect", "4 (Ernstig — exotherme reactie, bijtspatten)", "—"])
add_row(t, ["Risicoscore", "8 (Hoog)", "—"])

add_heading("7.1.2 Risico 2: Lekkage zonder opvang", level=3)
t = doc.add_table(rows=1, cols=3)
set_table_borders(t)
add_header_row(t, ["Aspect", "Preventief", "Repressief"])
add_row(t, ["Maatregel", "Lekbakken 110% grootste verpakking\nWekelijkse visuele inspectie\nVerpakkingsintegriteit controle", "Absorptiemateriaal beschikbaar\nInstructiekaart lekkageprocedure\nNooddouche bereikbaar"])
add_row(t, ["Waarschijnlijkheid", "3 (Mogelijk)", "—"])
add_row(t, ["Effect", "3 (Matig — bodemverontreiniging, huidcontact)", "—"])
add_row(t, ["Risicoscore", "9 (Hoog)", "—"])

add_heading("7.1.3 Risico 3: Onvoldoende instructie", level=3)
t = doc.add_table(rows=1, cols=3)
set_table_borders(t)
add_header_row(t, ["Aspect", "Preventief", "Repressief"])
add_row(t, ["Maatregel", "Jaarlijkse instructie verplicht\nInstructiekaarten bij opslag\nOpleidingsmatrix per functie", "Directe aansturing bij incident\nHSEQ Manager beschikbaar\nBuddy-systeem nieuwe medewerkers"])
add_row(t, ["Waarschijnlijkheid", "3 (Mogelijk)", "—"])
add_row(t, ["Effect", "3 (Matig — foutief handelen)", "—"])
add_row(t, ["Risicoscore", "9 (Hoog)", "—"])

add_para(
    "Alle drie de risico's scoren Hoog (≥ 6). Dit rechtvaardigt de inzet van zowel "
    "preventieve als repressieve maatregelen. De implementatie van lekbakken, vakmarkeringen "
    "en een gestructureerd instructieprogramma reduceert de waarschijnlijkheid naar niveau 1, "
    "waarmee het residuale risico aanvaardbaar wordt (score ≤ 4)."
)

# ============================================================
# 8. BRANDPREVENTIE
# ============================================================
add_heading("8. Brandpreventie", level=1)

add_para(
    "De bij Phoenix Metals opgeslagen stoffen (ADR-klasse 8, onbrandbaar) vormen geen "
    "primair brandgevaar. Desalniettemin vereist PGS 15:2025 brandpreventieve maatregelen "
    "om de opslaglocatie te beschermen tegen brand van buitenaf en om de gevolgen van een "
    "incident te beperken."
)

add_heading("8.1 Brandcompartimentering", level=2)
add_para(
    "De opslaglocatie bevindt zich in één brandcompartiment. De maximale oppervlakte bedraagt "
    "1.000 m² voor het basisveiligheidsniveau. De constructieve afscheiding van het "
    "brandcompartiment moet voldoen aan de eisen van het Besluit bouw- en sloopwerken in het "
    "buitenland (Bbl). Brandwerende wanden, deuren en andere constructieve elementen moeten "
    "de branddoorslag gedurende de vereiste tijdseenheid voorkomen."
)

add_heading("8.2 Blusmiddelen", level=2)
add_para(
    "Bij de opslaglocatie dienen handblustoestellen aanwezig te zijn van het type dat geschikt "
    "is voor de opgeslagen stoffen. Voor bijtende stoffen (ADR 8) zijn poederblustoestellen "
    "(ABC-poeder) of CO₂-blustoestellen geschikt. De blustoestellen worden geplaatst bij de "
    "toegang(en) van de opslagruimte, op een hoogte van maximaal 1,50 m, met een onderlinge "
    "afstand zodanig dat de loopafstand tot een blustoestel niet meer dan 15 m bedraagt. "
    "De blustoestellen worden jaarlijks gekeurd door een erkend bedrijf."
)

add_heading("8.3 Brandweerbereikbaarheid", level=2)
add_para(
    "Maatregel 109 (M109) stelt eisen aan de bereikbaarheid van de opslaglocatie voor "
    "hulpdiensten. De opslagruimte moet bereikbaar zijn via voldoende brede toegangswegen "
    "(minimaal 3,5 m breedte voor brandweervoertuigen). Binnen de opslagruimte moeten "
    "doorgangen van minimaal 0,80 m breedte worden vrijgehouden voor evacuatie en "
    "hulpverlening. De locatie en indeling van de opslag worden opgenomen in het "
    "calamiteitenplan en gecommuniceerd aan de lokale brandweer."
)

# ============================================================
# 9. OPLEIDING EN INSTRUCTIE
# ============================================================
add_heading("9. Opleiding en Instructie", level=1)

add_para(
    "Maatregel 85 en 86 (M85/M86) vereisen dat alle personen die betrokken zijn bij de "
    "opslag van gevaarlijke stoffen beschikken over voldoende kennis en vaardigheden om "
    "veilig te werken. De opleidingsverplichtingen zijn vastgelegd in onderstaande matrix."
)

t = doc.add_table(rows=1, cols=5)
set_table_borders(t)
add_header_row(t, ["Onderwerp", "Medewerkers", "Lab Manager", "HSEQ Manager", "Aannemers"])
training = [
    ("Algemene instructie opslagregels", "Jaarlijks", "Jaarlijks", "Jaarlijks", "Voor aanvang"),
    ("SDS/VIB raadplegen", "Jaarlijks", "Jaarlijks", "Jaarlijks", "Voor aanvang"),
    ("PBM-gebruik", "Jaarlijks", "Jaarlijks", "Jaarlijks", "Voor aanvang"),
    ("Lekkageprocedure", "Jaarlijks", "Jaarlijks", "Jaarlijks", "Voor aanvang"),
    ("Eerstehulp bij blootstelling", "Jaarlijks", "Jaarlijks", "Tweejaarlijks", "Voor aanvang"),
    ("Calamiteitenplan", "Jaarlijks", "Jaarlijks", "Tweejaarlijks", "Voor aanvang"),
    ("Stoffenscheiding (Tabel 9)", "Bij introductie", "Jaarlijks", "Jaarlijks", "N.v.t."),
    ("Interne audit techniek", "N.v.t.", "N.v.t.", "Tweejaarlijks", "N.v.t."),
]
for r in training:
    add_row(t, list(r), bold_first=True)

add_para(
    "De instructie wordt gedocumenteerd en gearchiveerd. Medewerkers tekenen voor ontvangst "
    "en begrip. De HSEQ Manager bewaart de opleidingsregisters en plant herhalingen tijdig in."
)

# ============================================================
# 10. TOEZICHT EN HANDHAVING
# ============================================================
add_heading("10. Toezicht en Handhaving", level=1)

add_heading("10.1 Interne audits", level=2)
add_para(
    "De HSEQ Manager voert minimaal tweemaal per jaar een interne audit uit op de opslaglocatie. "
    "De audit toetst de naleving van dit beleid, de juistheid van het chemisch register, de "
    "staat van de lekbakken en etikettering, en de toepassing van de stoffenscheiding. "
    "Bevindingen worden gerangschikt naar ernst (kritiek, significant, observatie) en "
    "gedocumenteerd in een auditrapport. Correctieve acties worden binnen 30 werkdagen "
    "geïmplementeerd voor kritieke bevindingen en binnen 90 werkdagen voor significante bevindingen."
)

add_heading("10.2 Inspecties", level=2)
t = doc.add_table(rows=1, cols=4)
set_table_borders(t)
add_header_row(t, ["Frequentie", "Onderwerp", "Uitvoerder", "Registratie"])
insp = [
    ("Dagelijks", "Visuele check opslag, lekkages, orde", "Medewerker", "Logboek"),
    ("Wekelijks", "Lekbakken, etikettering, PBM-voorraad", "Lab Manager", "Inspectieformulier"),
    ("Maandelijks", "Chemisch register, verpakkingen, wegen", "HSEQ Manager", "Rapportage"),
]
for r in insp:
    add_row(t, list(r), bold_first=True)

add_heading("10.3 Non-compliance procedure", level=2)
add_para(
    "Bij constatering van niet-compliance volgt een gestructureerde aanpak. De HSEQ Manager "
    "stelt de ernst vast en initieert de juiste escalatie. Voor lichte overtredingen (bijv. "
    "verkeerd geplaatste verpakking) volgt een mondelinge corrigerende instructie en directe "
    "rechtzetting. Voor structurele of ernstige overtredingen (bijv. falen stoffenscheiding) "
    "volgt een schriftelijke waarschuwing met hersteltermijn. Bij acuut gevaar wordt de "
    "opslaglocatie direct gesloten totdat de situatie is hersteld. Herhaalde overtredingen "
    "door dezelfde persoon leiden tot escalatie naar de directie met mogelijk disciplinaire "
    "maatregelen."
)

# ============================================================
# 11. DOCUMENTBEHEER
# ============================================================
add_heading("11. Documentbeheer", level=1)

add_heading("11.1 Versiebeheer", level=2)
add_para(
    "Dit document is onderhevig aan formeel versiebeheer. Elke wijziging wordt gedocumenteerd "
    "in onderstaand overzicht, inclusief de aard van de wijziging, de datum en de goedkeurder."
)
t = doc.add_table(rows=1, cols=5)
set_table_borders(t)
add_header_row(t, ["Versie", "Datum", "Auteur", "Wijziging", "Goedkeuring"])
vers = [
    ("1.0", "26 april 2026", "JvG Consultancy", "Eerste uitgave", "Pending"),
]
for r in vers:
    add_row(t, list(r), bold_first=True)

add_heading("11.2 Herzieningstermijn", level=2)
add_para(
    "Dit beleid wordt minimaal eenmaal per jaar herzien door de HSEQ Manager. Tussentijdse "
    "herziening is vereist bij:"
)
add_bullet("Wijzigingen in het chemisch register (nieuwe stoffen, gewijzigde volumes)")
add_bullet("Wijzigingen in de geldende wet- of regelgeving")
add_bullet("Incidenten of bijna-ongelukken gerelateerd aan de opslag")
add_bullet("Herinrichting of verhuizing van de opslaglocatie")
add_bullet("Bevindingen uit interne of externe audits")

add_heading("11.3 Distributielijst", level=2)
t = doc.add_table(rows=1, cols=4)
set_table_borders(t)
add_header_row(t, ["Functie", "Naam", "Vorm", "Exemplaar"])
dist = [
    ("Directie", "Vrijgehouden", "Digitaal + Print", "1"),
    ("HSEQ Manager", "J. van Gemert", "Digitaal + Print", "1"),
    ("Lab Manager", "Vrijgehouden", "Digitaal + Print", "1"),
    ("UPD / Brandweer", "Vrijgehouden", "Digitaal", "1"),
    ("Archief", "JvG Consultancy", "Digitaal", "1"),
]
for r in dist:
    add_row(t, list(r), bold_first=True)

# ============================================================
# 12. BIJLAGEN
# ============================================================
add_heading("12. Bijlagen", level=1)

add_heading("Bijlage A: Chemisch Register Phoenix Metals", level=2)
add_para(
    "Het chemisch register bevat alle bij Phoenix Metals opgeslagen gevaarlijke stoffen "
    "met de relevante gegevens: CAS-nummer, ADR-klasse, verpakkingsgroep, volume, "
    "verpakkingsvorm en opslaglocatie. Het actuele register is opgenomen in het META-DOSSIER "
    "v1.0 (§1.1) en wordt separaat beheerd als werkdocument. Raadpleeg de HSEQ Manager voor "
    "de meest actuele versie."
)

add_heading("Bijlage B: Compatibiliteitsmatrix", level=2)
add_para(
    "De compatibiliteitsmatrix (Tabel 9, PGS 15 Bijlage E) geeft aan welke stofcombinaties "
    "gescheiden opslag vereisen. De Phoenix Metals-specifieke matrix is opgenomen in het "
    "META-DOSSIER v1.0 (§2.2) en bevat zes stofcombinaties met hun vereiste scheidingsniveau "
    "(A, B, V, of —). Deze matrix wordt jaarlijks geactualiseerd bij wijzigingen in het "
    "chemisch register."
)

add_heading("Bijlage C: Referenties PGS 15:2025 paragrafen", level=2)
t = doc.add_table(rows=1, cols=3)
set_table_borders(t)
add_header_row(t, ["Paragraaf", "Onderwerp", "Relevantie PM"])
refs = [
    ("MW1", "Zorgplicht", "Basisverplichting, altijd van toepassing"),
    ("M2", "Bestemde opslag", "Opslag in daartoe bestemde voorziening"),
    ("M14", "Werkvoorraad", "Beperking buiten opslag aanwezige hoeveelheid"),
    ("M15", "Max. oppervlakte brandcompartiment", "1.000 m² bij < 20.000 kg"),
    ("M30", "Vloeistofopvang", "Lekbakken 110% grootste verpakking"),
    ("M35", "Stoffenscheiding", "Conform Bijlage E, Tabel 9"),
    ("M36/M45", "Verpakkingsintegriteit", "Goedgekeurde verpakkingen, CLP-conform"),
    ("M77/M78", "Fysieke bescherming", "Botsbeveiliging bij transportmiddelen"),
    ("M85/M86", "Deskundigheid", "Opleiding, instructie, SDS beschikbaar"),
    ("M89", "Noodplan", "Calamiteitenplan opslag gevaarlijke stoffen"),
    ("M96", "VBB-installatie", "Niet van toepassing (basisniveau)"),
    ("M97", "Branddetectie + doormelding", "Niet van toepassing (basisniveau)"),
    ("M109", "Brandweerbereikbaarheid", "Toegankelijkheid hulpdiensten"),
    ("Bijlage E, Tabel 9", "Compatibiliteitsmatrix", "Scheiding ADR 8 ↔ ADR 8 = A"),
    ("Tabel 6", "Veiligheidsniveaus", "PM = basisniveau (< 10.000 kg)"),
    ("Tabel 7", "Drempelwaarden ondergrens", "ADR 8 PG II/III: 2.500 kg"),
    ("E.3", "Uitzondering < 10.000 kg", "Scheiding binnen vak via 2 m afstand"),
]
for r in refs:
    add_row(t, list(r), bold_first=True)

# ---- Bronverwijzingen ----
doc.add_paragraph()
add_heading("Bronnen", level=1)
add_para("[1] PGS 15:2025, Publicatiereeks Gevaarlijke Stoffen, versie 1.0, 2025")
add_para("[2] Omgevingswet, Besluit kwaliteit leefomgeving (Bkl), art. 4.12-4.18")
add_para("[3] Arbeidsomstandighedenwet, Arbobesluit art. 4.1c (RI&E)")
add_para("[4] ADR 2025, Accordo européenne relatif au transport international des marchandises Dangereuses par Route")
add_para("[5] CLP-Verordening (EG) Nr. 1272/2008")
add_para("[6] REACH-Verordening (EG) Nr. 1907/2006")
add_para("[7] META-DOSSIER PGS-15 Compliance — Phoenix Metals IJmuiden, v1.0, 26 april 2026")
add_para("[8] Phoenix Metals — Chemical Register v2.1.0")

# ---- Save ----
os.makedirs(os.path.dirname(OUT), exist_ok=True)
doc.save(OUT)
print(f"✅ Bestand opgeslagen: {OUT}")

# ---- Verify ----
size = os.path.getsize(OUT)
print(f"📦 Bestandsgrootte: {size:,} bytes")

# Count words (rough)
word_count = 0
for p in doc.paragraphs:
    word_count += len(p.text.split())
for t in doc.tables:
    for row in t.rows:
        for cell in row.cells:
            word_count += len(cell.text.split())
print(f"📝 Geschat woordenaantal: {word_count:,}")
