#!/usr/bin/env python3
"""Shared DOCX helpers — JvG Consultancy branding (MASTER_STYLEGUIDE v1.5)."""
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

PRIMARY = "003366"; SUCCESS = "00A859"; WARNING = "F59E0B"; ERROR = "EF4444"
TEXT_DARK = "1F2937"; TEXT_SEC = "374151"; BG_CARD = "F8F9FA"
LOGO_COLOR = "/root/projects/jg/assets/branding/jvg-consultancy-logo.png"
LOGO_WHITE = "/root/projects/jg/assets/branding/jvg-logo-white-medium.png"

def shade(cell, hex_color):
    tcPr = cell._tc.get_or_add_tcPr()
    shd = OxmlElement('w:shd'); shd.set(qn('w:val'), 'clear')
    shd.set(qn('w:color'), 'auto'); shd.set(qn('w:fill'), hex_color)
    tcPr.append(shd)

def set_cell_margins(cell, top=60, start=100, bottom=60, end=100):
    tcPr = cell._tc.get_or_add_tcPr()
    mar = OxmlElement('w:tcMar')
    for tag, val in (('top', top), ('start', start), ('bottom', bottom), ('end', end)):
        el = OxmlElement(f'w:{tag}'); el.set(qn('w:w'), str(val)); el.set(qn('w:type'), 'dxa')
        mar.append(el)
    tcPr.append(mar)

def cell_text(cell, text, bold=False, color=TEXT_DARK, size=9.5, align=None):
    cell.text = ""
    p = cell.paragraphs[0]
    if align: p.alignment = align
    for i, line in enumerate(str(text).split("\n")):
        if i > 0: p = cell.add_paragraph()
        r = p.add_run(line); r.bold = bold; r.font.size = Pt(size)
        r.font.color.rgb = RGBColor.from_string(color); r.font.name = "Calibri"
    set_cell_margins(cell)

def style_base(doc):
    st = doc.styles['Normal']
    st.font.name = "Calibri"; st.font.size = Pt(11)
    st.font.color.rgb = RGBColor.from_string(TEXT_DARK)
    st.paragraph_format.space_after = Pt(6)
    st.paragraph_format.line_spacing = 1.15

def h1(doc, text):
    p = doc.add_paragraph(); p.paragraph_format.space_before = Pt(18); p.paragraph_format.space_after = Pt(8)
    r = p.add_run(text); r.bold = True; r.font.size = Pt(16)
    r.font.color.rgb = RGBColor.from_string(PRIMARY); r.font.name = "Calibri"
    pPr = p._p.get_or_add_pPr()
    pbdr = OxmlElement('w:pBdr'); b = OxmlElement('w:bottom')
    b.set(qn('w:val'), 'single'); b.set(qn('w:sz'), '12'); b.set(qn('w:space'), '4'); b.set(qn('w:color'), PRIMARY)
    pbdr.append(b); pPr.append(pbdr)
    return p

def h2(doc, text):
    p = doc.add_paragraph(); p.paragraph_format.space_before = Pt(12); p.paragraph_format.space_after = Pt(6)
    r = p.add_run(text); r.bold = True; r.font.size = Pt(13)
    r.font.color.rgb = RGBColor.from_string(PRIMARY); r.font.name = "Calibri"
    return p

def h3(doc, text, color=PRIMARY):
    p = doc.add_paragraph(); p.paragraph_format.space_before = Pt(10); p.paragraph_format.space_after = Pt(4)
    r = p.add_run(text); r.bold = True; r.font.size = Pt(11.5)
    r.font.color.rgb = RGBColor.from_string(color); r.font.name = "Calibri"
    return p

def body(doc, text, bold_lead=None, size=11, italic=False):
    p = doc.add_paragraph()
    if bold_lead:
        r = p.add_run(bold_lead); r.bold = True; r.font.size = Pt(size)
        r.font.color.rgb = RGBColor.from_string(TEXT_DARK); r.font.name = "Calibri"
    r = p.add_run(text); r.font.size = Pt(size); r.italic = italic
    r.font.color.rgb = RGBColor.from_string(TEXT_DARK); r.font.name = "Calibri"
    return p

def bullet(doc, text, bold_lead=None):
    p = doc.add_paragraph(style='List Bullet')
    if bold_lead:
        r = p.add_run(bold_lead); r.bold = True
        r.font.color.rgb = RGBColor.from_string(TEXT_DARK); r.font.name = "Calibri"
    r = p.add_run(text); r.font.color.rgb = RGBColor.from_string(TEXT_DARK); r.font.name = "Calibri"
    return p

def prio_color(val):
    v = str(val).strip()
    if v.startswith("P1"): return (ERROR, True)
    if v.startswith("P2"): return ("B45309", True)
    if "Conform" in v: return (SUCCESS, True)
    return (TEXT_DARK, False)

def make_table(doc, headers, rows, widths=None, size=9.0, color_cols=None):
    """color_cols: dict col_index -> color function (val)->(color,bold) or None for default."""
    t = doc.add_table(rows=1, cols=len(headers))
    t.style = 'Table Grid'; t.alignment = WD_TABLE_ALIGNMENT.CENTER
    t.autofit = False
    for i, hdr in enumerate(headers):
        c = t.rows[0].cells[i]
        cell_text(c, hdr, bold=True, color="FFFFFF", size=size)
        shade(c, PRIMARY)
        if widths: c.width = Cm(widths[i])
    for ri, row in enumerate(rows):
        cells = t.add_row().cells
        for ci, val in enumerate(row):
            col, bold = TEXT_DARK, False
            fn = color_cols.get(ci) if color_cols else None
            if fn:
                col, bold = fn(val)
            cell_text(cells[ci], val, bold=bold, color=col, size=size)
            if fn and col != TEXT_DARK:
                shade(cells[ci], "FEF2F2" if col == ERROR else ("FFFBEB" if col == "B45309" else "F0FDF4"))
            elif ri % 2 == 1:
                shade(cells[ci], BG_CARD)
            if widths: cells[ci].width = Cm(widths[ci])
    return t

def add_page_field(paragraph):
    run = paragraph.add_run()
    f1 = OxmlElement('w:fldChar'); f1.set(qn('w:fldCharType'), 'begin')
    it = OxmlElement('w:instrText'); it.set(qn('xml:space'), 'preserve'); it.text = ' PAGE '
    f2 = OxmlElement('w:fldChar'); f2.set(qn('w:fldCharType'), 'end')
    run._r.append(f1); run._r.append(it); run._r.append(f2)
    run.font.size = Pt(8.5); run.font.color.rgb = RGBColor.from_string("FFFFFF"); run.font.name = "Calibri"

def header_footer(doc, title_short, footer_left):
    sec = doc.sections[0]
    sec.header_distance = Cm(0.6); sec.footer_distance = Cm(0.6)
    hdr = sec.header
    ht = hdr.add_table(rows=1, cols=2, width=Cm(17.0))
    ht.style = 'Table Grid'; ht.autofit = False
    c0, c1 = ht.rows[0].cells
    c0.width = Cm(13.8); c1.width = Cm(3.2)
    for c in (c0, c1):
        shade(c, PRIMARY); set_cell_margins(c, 80, 140, 80, 140)
    c0.text = ""
    p = c0.paragraphs[0]
    r = p.add_run(title_short); r.bold = True; r.font.size = Pt(10)
    r.font.color.rgb = RGBColor.from_string("FFFFFF"); r.font.name = "Calibri"
    r2 = p.add_run("\nJvG Consultancy — Safety • Governance • Advisory  |  HSEQ Divisie")
    r2.font.size = Pt(8); r2.font.color.rgb = RGBColor.from_string("D1D5DB"); r2.font.name = "Calibri"
    c1.text = ""
    p1 = c1.paragraphs[0]; p1.alignment = WD_ALIGN_PARAGRAPH.RIGHT
    p1.add_run().add_picture(LOGO_WHITE, width=Cm(2.0), height=Cm(1.79))
    ftr = sec.footer
    ft = ftr.add_table(rows=1, cols=1, width=Cm(17.0))
    ft.style = 'Table Grid'
    fc = ft.rows[0].cells[0]; shade(fc, TEXT_SEC); set_cell_margins(fc, 60, 140, 60, 140)
    fc.text = ""
    fp = fc.paragraphs[0]; fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = fp.add_run(f"{footer_left}  |  v1.0  |  24-08-2026  |  Pagina ")
    r.font.size = Pt(8.5); r.font.color.rgb = RGBColor.from_string("FFFFFF"); r.font.name = "Calibri"
    add_page_field(fp)
    r = fp.add_run("  |  JvG Consultancy")
    r.font.size = Pt(8.5); r.font.color.rgb = RGBColor.from_string("FFFFFF"); r.font.name = "Calibri"

def cover(doc, doc_type, title, subtitle, meta_rows):
    # Logo (kleur, transparant, ratio 1.115:1)
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(24); p.paragraph_format.space_after = Pt(4)
    p.add_run().add_picture(LOGO_COLOR, width=Cm(4.0), height=Cm(3.59))
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run("JvG CONSULTANCY"); r.bold = True; r.font.size = Pt(14)
    r.font.color.rgb = RGBColor.from_string(PRIMARY); r.font.name = "Calibri"
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run("Safety • Governance • Advisory"); r.font.size = Pt(10)
    r.font.color.rgb = RGBColor.from_string(TEXT_SEC); r.font.name = "Calibri"
    p.paragraph_format.space_after = Pt(24)
    # Titelblok (donkerblauw)
    t = doc.add_table(rows=1, cols=1); t.style = 'Table Grid'; t.alignment = WD_TABLE_ALIGNMENT.CENTER
    c = t.rows[0].cells[0]; shade(c, PRIMARY); set_cell_margins(c, 300, 300, 300, 300)
    c.text = ""
    p = c.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run(doc_type); r.bold = True; r.font.size = Pt(13)
    r.font.color.rgb = RGBColor.from_string("FFFFFF"); r.font.name = "Calibri"
    p2 = c.add_paragraph(); p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p2.add_run(title); r.bold = True; r.font.size = Pt(24)
    r.font.color.rgb = RGBColor.from_string("FFFFFF"); r.font.name = "Calibri"
    p3 = c.add_paragraph(); p3.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p3.add_run(subtitle); r.font.size = Pt(11)
    r.font.color.rgb = RGBColor.from_string("D1D5DB"); r.font.name = "Calibri"
    doc.add_paragraph()
    # Meta-tabel
    make_table(doc, ["Gegeven", "Waarde"], meta_rows, widths=[5.0, 12.0], size=10)
    doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run("Vertrouwelijk — uitsluitend bestemd voor opdrachtgever en projectorganisatie")
    r.font.size = Pt(8.5); r.italic = True
    r.font.color.rgb = RGBColor.from_string(TEXT_SEC); r.font.name = "Calibri"
    doc.add_page_break()
