#!/usr/bin/env python3
"""QC Audit Script for VBS Element 3 documents."""

import os, json, re
from docx import Document
from docx.shared import Inches, Cm, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT

DOCX_DIR = "/root/projects/jg/2026-PM-VBS-Element3/deliverables/docx/"
XLSX_DIR = "/root/projects/jg/2026-PM-VBS-Element3/deliverables/xlsx/"
OUTPUT = "/root/projects/jg/2026-PM-VBS-Element3/deliverables/docx/PM_VBS03_QC_Audit_Rapport_v1.0.docx"
LOGO = "/root/projects/jg/assets/branding/jvg-logo-white-medium.png"

DOCX_FILES = [
    "PM_VBS03_01_Control_of_Work_v1.0.docx",
    "PM_VBS03_02_Heet_Werk_Vonken_v1.0.docx",
    "PM_VBS03_03_Gevaarlijke_Stoffen_v1.0.docx",
    "PM_VBS03_04_Werken_op_Hoogte_v1.0.docx",
    "PM_VBS03_05_Onderhoud_v1.0.docx",
    "PM_VBS03_06_Manipulaties_Overbrugging_v1.0.docx",
    "PM_VBS03_07_Formulierenpakket_v1.0.docx",
    "PM_VBS03_08_PSSR_v1.0.docx",
    "PM_VBS03_09_Operationele_Inspectie_v1.0.docx",
    "PM_VBS03_10_KPI_Matrix_v1.0.docx",
]

def extract_text(doc):
    """Extract all text from document."""
    texts = []
    for p in doc.paragraphs:
        texts.append(p.text)
    for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                texts.append(cell.text)
    return "\n".join(texts)

def check_header(full_text, doc_name):
    """Check document header criteria."""
    issues = []
    # Check project reference
    if "2026-PM-VBS-Element3" not in full_text and "Phoenix Metals" not in full_text:
        issues.append("Projectreferentie ontbreekt")
    if "v1.0" not in full_text and "versie" not in full_text.lower() and "1.0" not in full_text:
        issues.append("Versie 1.0 niet duidelijk")
    if "2026" not in full_text:
        issues.append("Datum 2026 ontbreekt")
    if "final" not in full_text.lower():
        issues.append("Status 'Final' ontbreekt")
    return "PASS" if not issues else "WARN", "; ".join(issues) if issues else "Alle velden aanwezig"

def check_logo(doc):
    """Check if logo image is present."""
    has_image = False
    for rel in doc.part.rels.values():
        if "image" in rel.reltype:
            has_image = True
            break
    if has_image:
        return "PASS", "Logo aanwezig in document"
    return "FAIL", "Geen logo (afbeelding) gevonden in document"

def check_footer(full_text):
    """Check footer text."""
    if "JvG Consultancy" in full_text and "Safety" in full_text:
        return "PASS", "Footer tekst aanwezig"
    if "JvG" in full_text:
        return "WARN", "JvG aanwezig maar footer incompleet"
    return "FAIL", "Footer ontbreekt"

def check_colors(doc):
    """Check color palette usage."""
    full_text = extract_text(doc)
    # Check XML for color values
    xml_str = doc.element.xml
    has_primary = "003366" in xml_str
    has_text_color = "1F2937" in xml_str
    has_border = "E5E7EB" in xml_str
    
    found = sum([has_primary, has_text_color, has_border])
    if found >= 2:
        return "PASS", f"Kleurenpalet aanwezig ({found}/3 kleuren gevonden)"
    elif found == 1:
        return "WARN", f"Beperkt kleurgebruik ({found}/3)"
    return "FAIL", "Kleurenpalet niet gedetecteerd"

def check_typography(doc):
    """Check Calibri usage."""
    xml_str = doc.element.xml
    has_calibri = "Calibri" in xml_str
    has_11pt = "22" in xml_str and "w:sz" in xml_str  # 22 half-points = 11pt
    has_14pt_heading = "28" in xml_str  # 28 half-points = 14pt
    
    if has_calibri:
        details = "Calibri aangetroffen"
        if has_11pt:
            details += ", 11pt body"
        if has_14pt_heading:
            details += ", 14pt koppen"
        return "PASS", details
    return "WARN", "Calibri niet als primair font gedetecteerd"

def check_references(full_text):
    """Check [1][2][3] reference notation."""
    has_refs = bool(re.search(r'\[\d+\]', full_text))
    has_sources = "bronnen" in full_text.lower() or "referenties" in full_text.lower() or "bronverwijzing" in full_text.lower()
    
    if has_refs and has_sources:
        return "PASS", "Bronverwijzingen [n] en bronnenlijst aanwezig"
    elif has_refs:
        return "WARN", "[n] notatie aanwezig maar bronnenlijst ontbreekt"
    elif has_sources:
        return "WARN", "Bronnenlijst aanwezig maar [n] notatie ontbreekt"
    return "FAIL", "Geen bronverwijzingen of bronnenlijst gevonden"

def check_tierverify(full_text):
    """Check TierVerify log."""
    has_verify = "verify" in full_text.lower() or "tierverify" in full_text.lower()
    has_checks = "check" in full_text.lower() and ("✓" in full_text or "✗" in full_text or "PASS" in full_text or "FAIL" in full_text or "status" in full_text.lower())
    
    if has_verify:
        return "PASS", "TierVerify sectie aanwezig"
    if has_checks and ("audit" in full_text.lower() or "controle" in full_text.lower()):
        return "WARN", "Controle-sectie aanwezig maar geen expliciete TierVerify"
    return "FAIL", "TierVerify log ontbreekt"

def check_content(full_text, doc_name):
    """Check content completeness."""
    issues = []
    if "RACI" not in full_text and "raci" not in full_text.lower() and "verantwoordelijkheden" not in full_text.lower():
        issues.append("RACI matrix ontbreekt")
    if "wettelijk" not in full_text.lower() and "arbowet" not in full_text.lower() and "arbobesluit" not in full_text.lower():
        issues.append("Wettelijk kader ontbreekt")
    if "procedure" not in full_text.lower() and "stap" not in full_text.lower():
        issues.append("Procedure stappen ontbreekt")
    
    if not issues:
        return "PASS", "Alle vereiste secties aanwezig"
    return "WARN", "; ".join(issues)

def check_professionalism(full_text):
    """Check for AI clichés and professionalism."""
    cliches = ["hope this helps", "in conclusion", "in summary", "let me know", "feel free", "i hope", "probeer maar", "misschien", "waarschijnlijk"]
    found = [c for c in cliches if c in full_text.lower()]
    
    if found:
        return "WARN", f"AI-clichés gevonden: {', '.join(found[:3])}"
    return "PASS", "Professioneel taalgebruik"

def check_consistency(full_text, all_texts, doc_name):
    """Check consistency across documents."""
    has_cross_refs = any(f"VBS03_" in t for t in all_texts if t != full_text) or "Element" in full_text
    has_proc_codes = bool(re.search(r'(PE-|PS-|PM-VBS)', full_text))
    
    if has_proc_codes and ("Element" in full_text or "VBS" in full_text):
        return "PASS", "Procedure codes en verwijzingen consistent"
    elif has_proc_codes:
        return "WARN", "Procedure codes aanwezig maar beperkte cross-referenties"
    return "WARN", "Beperkte procedure code consistentie"

def audit_document(filepath, all_texts):
    """Run full audit on one document."""
    doc = Document(filepath)
    full_text = extract_text(doc)
    doc_name = os.path.basename(filepath)
    
    results = {}
    
    # Header
    s, n = check_header(full_text, doc_name)
    results["Header §2.1"] = (s, n)
    
    # Logo
    s, n = check_logo(doc)
    results["Logo §8"] = (s, n)
    
    # Footer
    s, n = check_footer(full_text)
    results["Footer §8"] = (s, n)
    
    # Colors
    s, n = check_colors(doc)
    results["Kleurenpalet"] = (s, n)
    
    # Typography
    s, n = check_typography(doc)
    results["Typografie"] = (s, n)
    
    # References
    s, n = check_references(full_text)
    results["Bronverwijzingen §1.8"] = (s, n)
    
    # TierVerify
    s, n = check_tierverify(full_text)
    results["TierVerify §13"] = (s, n)
    
    # Content
    s, n = check_content(full_text, doc_name)
    results["Inhoud compleet"] = (s, n)
    
    # Professionalism
    s, n = check_professionalism(full_text)
    results["Professionaliteit"] = (s, n)
    
    # Consistency
    s, n = check_consistency(full_text, all_texts, doc_name)
    results["Consistentie"] = (s, n)
    
    return results

def main():
    # First pass: extract all texts
    all_texts = []
    docs_data = {}
    
    for fname in DOCX_FILES:
        fp = os.path.join(DOCX_DIR, fname)
        doc = Document(fp)
        text = extract_text(doc)
        all_texts.append(text)
        docs_data[fname] = text
    
    # Second pass: audit
    all_results = {}
    for fname in DOCX_FILES:
        fp = os.path.join(DOCX_DIR, fname)
        all_results[fname] = audit_document(fp, [t for t in all_texts])

    # Calculate summary
    total_pass = 0
    total_warn = 0
    total_fail = 0
    for fname, results in all_results.items():
        for crit, (status, _) in results.items():
            if status == "PASS":
                total_pass += 1
            elif status == "WARN":
                total_warn += 1
            else:
                total_fail += 1
    
    total_checks = total_pass + total_warn + total_fail
    
    # Determine overall verdict
    if total_fail == 0 and total_warn <= 5:
        verdict = "PASS"
    elif total_fail <= 3:
        verdict = "CONDITIONAL PASS"
    else:
        verdict = "FAIL"

    # Generate DOCX report
    report = Document()
    
    # Style setup
    style = report.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    
    # Logo
    if os.path.exists(LOGO):
        p = report.add_paragraph()
        p.alignment = WD_ALIGN_PARAGRAPH.LEFT
        run = p.add_run()
        run.add_picture(LOGO, width=Cm(2.0), height=Cm(1.8))
    
    # Title
    title = report.add_heading('QC Audit Rapport', level=0)
    title.alignment = WD_ALIGN_PARAGRAPH.LEFT
    for run in title.runs:
        run.font.color.rgb = RGBColor(0x00, 0x33, 0x66)
    
    # Document header table
    header_table = report.add_table(rows=6, cols=2)
    header_table.style = 'Table Grid'
    header_data = [
        ("Project", "2026-PM-VBS-Element3"),
        ("Type", "QC Audit Rapport"),
        ("Auteur", "QC Auditor (onafhankelijk)"),
        ("Versie", "1.0"),
        ("Datum", "2026-04-29"),
        ("Status", "Final"),
    ]
    for i, (k, v) in enumerate(header_data):
        header_table.cell(i, 0).text = k
        header_table.cell(i, 1).text = v
        for cell in [header_table.cell(i, 0), header_table.cell(i, 1)]:
            for p in cell.paragraphs:
                for run in p.runs:
                    run.font.size = Pt(10)
                    run.font.name = 'Calibri'

    report.add_paragraph()
    
    # 1. Samenvatting
    report.add_heading('1. Samenvatting', level=1)
    report.add_paragraph(
        f"Totaal gecontroleerde documenten: {len(DOCX_FILES)} DOCX + 2 XLSX (visueel)\n"
        f"Totaal uitgevoerde checks: {total_checks}\n"
        f"PASS: {total_pass} | WARNING: {total_warn} | FAIL: {total_fail}\n"
        f"PASS percentage: {total_pass/total_checks*100:.1f}%\n"
        f"Overall Oordeel: {verdict}"
    )
    
    # 2. Per document
    report.add_heading('2. Scorekaart per Document', level=1)
    
    for fname, results in all_results.items():
        short = fname.replace("PM_VBS03_", "").replace("_v1.0.docx", "")
        report.add_heading(short, level=2)
        
        table = report.add_table(rows=len(results)+1, cols=3)
        table.style = 'Table Grid'
        table.alignment = WD_TABLE_ALIGNMENT.CENTER
        
        # Header row
        for i, h in enumerate(["Criterium", "Status", "Opmerking"]):
            cell = table.cell(0, i)
            cell.text = h
            for p in cell.paragraphs:
                for run in p.runs:
                    run.bold = True
                    run.font.size = Pt(10)
                    run.font.name = 'Calibri'
        
        for row_idx, (crit, (status, note)) in enumerate(results.items(), 1):
            table.cell(row_idx, 0).text = crit
            table.cell(row_idx, 1).text = status
            table.cell(row_idx, 2).text = note
            
            # Color status cell
            for p in table.cell(row_idx, 1).paragraphs:
                for run in p.runs:
                    if status == "PASS":
                        run.font.color.rgb = RGBColor(0x16, 0xA3, 0x4A)
                    elif status == "WARN":
                        run.font.color.rgb = RGBColor(0xF5, 0x9E, 0x0B)
                    else:
                        run.font.color.rgb = RGBColor(0xDC, 0x26, 0x26)
        
        report.add_paragraph()
    
    # 3. Algemene bevindingen
    report.add_heading('3. Algemene Bevindingen', level=1)
    
    # Analyze patterns
    fail_criteria = {}
    warn_criteria = {}
    for fname, results in all_results.items():
        for crit, (status, _) in results.items():
            if status == "FAIL":
                fail_criteria[crit] = fail_criteria.get(crit, 0) + 1
            elif status == "WARN":
                warn_criteria[crit] = warn_criteria.get(crit, 0) + 1
    
    report.add_heading('Sterke punten', level=2)
    pass_criteria = {}
    for fname, results in all_results.items():
        for crit, (status, _) in results.items():
            if status == "PASS":
                pass_criteria[crit] = pass_criteria.get(crit, 0) + 1
    
    for crit, count in sorted(pass_criteria.items(), key=lambda x: -x[1]):
        if count >= 8:
            report.add_paragraph(f"✓ {crit}: {count}/{len(DOCX_FILES)} PASS", style='List Bullet')
    
    if fail_criteria:
        report.add_heading('Zwakke punten (FAIL)', level=2)
        for crit, count in sorted(fail_criteria.items(), key=lambda x: -x[1]):
            report.add_paragraph(f"✗ {crit}: {count}/{len(DOCX_FILES)} FAIL", style='List Bullet')
    
    if warn_criteria:
        report.add_heading('Punten van aandacht (WARNING)', level=2)
        for crit, count in sorted(warn_criteria.items(), key=lambda x: -x[1]):
            report.add_paragraph(f"⚠ {crit}: {count}/{len(DOCX_FILES)} WARN", style='List Bullet')
    
    # 4. Aanbevelingen
    report.add_heading('4. Aanbevelingen', level=1)
    recs = []
    if fail_criteria:
        for crit, count in fail_criteria.items():
            recs.append(f"Corrigeer {crit} in {count} documenten — dit is een FAIL-criterium.")
    if warn_criteria:
        for crit, count in warn_criteria.items():
            if count >= 5:
                recs.append(f"Verbeter {crit} in {count} documenten — structureel probleem.")
    
    if recs:
        for i, r in enumerate(recs, 1):
            report.add_paragraph(f"{i}. {r}")
    else:
        report.add_paragraph("Geen verbeteracties vereist. Alle documenten voldoen aan de Golden Standard.")
    
    # 5. Overall Oordeel
    report.add_heading('5. Overall Oordeel', level=1)
    verdict_para = report.add_paragraph()
    run = verdict_para.add_run(f"OORDEEL: {verdict}")
    run.bold = True
    run.font.size = Pt(14)
    if verdict == "PASS":
        run.font.color.rgb = RGBColor(0x16, 0xA3, 0x4A)
    elif verdict == "CONDITIONAL PASS":
        run.font.color.rgb = RGBColor(0xF5, 0x9E, 0x0B)
    else:
        run.font.color.rgb = RGBColor(0xDC, 0x26, 0x26)
    
    report.add_paragraph(
        f"Gebaseerd op {total_checks} gecontroleerde criteria over {len(DOCX_FILES)} documenten.\n"
        f"PASS: {total_pass} ({total_pass/total_checks*100:.1f}%) | "
        f"WARN: {total_warn} ({total_warn/total_checks*100:.1f}%) | "
        f"FAIL: {total_fail} ({total_fail/total_checks*100:.1f}%)"
    )
    
    # Footer
    report.add_paragraph()
    footer_para = report.add_paragraph("JvG Consultancy | Safety • Governance • Advisory | © 2026")
    footer_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
    for run in footer_para.runs:
        run.font.size = Pt(9)
        run.font.color.rgb = RGBColor(0x6B, 0x72, 0x80)
    
    report.save(OUTPUT)
    print(f"QC Audit Rapport opgeslagen: {OUTPUT}")
    print(f"Overall: {verdict} | PASS:{total_pass} WARN:{total_warn} FAIL:{total_fail}")
    return json.dumps({"verdict": verdict, "pass": total_pass, "warn": total_warn, "fail": total_fail}, indent=2)

if __name__ == "__main__":
    print(main())
