#!/usr/bin/env python3
"""Retrofit cross-references into Doc 1-5."""

import shutil
import copy
from pathlib import Path
from docx import Document
from docx.shared import Pt, Cm, RGBColor, Inches
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml

DELIV = Path("/root/projects/jg/2026-PM-VBS-Element1/deliverables")
ARCHIVE = Path("/root/projects/jg/2026-PM-VBS-Element1/archive")

DOCS = [
    {"nr": 1, "file": "PM_VBS01_01_PBZO_Beleidsdocument_v1.1.docx", "new": "PM_VBS01_01_PBZO_Beleidsdocument_v1.2.docx", "code": "PS-230", "title": "PBZO Beleidsdocument"},
    {"nr": 2, "file": "PM_VBS01_02_Functieprofielen_Veiligheid_v1.0.docx", "new": "PM_VBS01_02_Functieprofielen_Veiligheid_v1.1.docx", "code": "PE-310-02", "title": "Functieprofielen Veiligheid"},
    {"nr": 3, "file": "PM_VBS01_03_Organigram_Veiligheid_v1.0.docx", "new": "PM_VBS01_03_Organigram_Veiligheid_v1.1.docx", "code": "PE-310-03", "title": "Organigram Veiligheidsstructuur"},
    {"nr": 4, "file": "PM_VBS01_04_Training_Matrix_v1.0.docx", "new": "PM_VBS01_04_Training_Matrix_v1.1.docx", "code": "FM-310-01-01", "title": "Training Matrix"},
    {"nr": 5, "file": "PM_VBS01_05_Inwerkprogramma_v1.0.docx", "new": "PM_VBS01_05_Inwerkprogramma_v1.1.docx", "code": "PE-310-01", "title": "Inwerkprogramma Nieuwe Medewerkers"},
]

ALL_REFS = [
    {"nr": 1, "code": "PS-230", "title": "PBZO Beleidsdocument"},
    {"nr": 2, "code": "PE-310-02", "title": "Functieprofielen Veiligheid"},
    {"nr": 3, "code": "PE-310-03", "title": "Organigram Veiligheidsstructuur"},
    {"nr": 4, "code": "FM-310-01-01", "title": "Training Matrix"},
    {"nr": 5, "code": "PE-310-01", "title": "Inwerkprogramma Nieuwe Medewerkers"},
]

# Specific relationships per document (row = current doc, col = referenced doc)
RELATIONSHIPS = {
    1: {  # PBZO
        1: "(dit document)",
        2: "Functieprofielen van de in het beleid gedefinieerde veiligheidsrollen",
        3: "Organisatorische structuur die het beleid inricht",
        4: "Trainingseisen afgeleid uit de beleidsdoelstellingen",
        5: "Inwerkprogramma voor nieuwe medewerkers conform beleidskader",
    },
    2: {  # Functieprofielen
        1: "Strategisch kader voor veiligheidsverantwoordelijkheden",
        2: "(dit document)",
        3: "Organisatorische hiërarchie waarbinnen functies gedefinieerd zijn",
        4: "Trainingen en competenties vereist per functieprofiel",
        5: "Inwerktrajecten gekoppeld aan functieprofielen",
    },
    3: {  # Organigram
        1: "Beleidskader dat de organisatiestructuur onderbouwt",
        2: "Functieprofielen verbonden aan de organigramposities",
        3: "(dit document)",
        4: "Trainingsverplichtingen per organisatielaag",
        5: "Inwerkprogramma's per functieniveau in de structuur",
    },
    4: {  # Training Matrix
        1: "Beleidsdoelstellingen die trainingsvereisten bepalen",
        2: "Functieprofielen die als basis dienen voor trainingsbehoeften",
        3: "Organisatiestructuur die trainingsniveaus bepaalt",
        4: "(dit document)",
        5: "Inwerkprogramma als onderdeel van het totale trainingsaanbod",
    },
    5: {  # Inwerkprogramma
        1: "Beleidskader waarbinnen het inwerkprogramma valt",
        2: "Functieprofielen waaraan nieuwe medewerkers moeten voldoen",
        3: "Organisatorische inbedding van de nieuwe medewerker",
        4: "Trainingen die onderdeel zijn van het inwerktraject",
        5: "(dit document)",
    },
}

# Text cross-references: (doc_nr_to_modify, search_text_hint, ref_to_insert)
# We'll search for key phrases and insert refs after them
TEXT_REFS = {
    1: [  # PBZO
        # Where roles/organization discussed → ref to Doc 2 and Doc 3
    ],
    2: [  # Functieprofielen → training ref
    ],
    3: [],
    4: [  # Training Matrix → inwerkprogramma
    ],
    5: [  # Inwerkprogramma → rollen
    ],
}


def set_cell_shading(cell, color_hex):
    """Set cell background shading."""
    shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="{color_hex}" w:val="clear"/>')
    cell._tc.get_or_add_tcPr().append(shading)


def add_related_docs_section(doc, current_doc_nr):
    """Add 'Gerelateerde Documenten' section before Bronverwijzingen/TierVerify or at end."""
    # Find insertion point
    insert_idx = None
    for i, para in enumerate(doc.paragraphs):
        text = para.text.strip().lower()
        if any(kw in text for kw in ['bronverwijzingen', 'bronverwijzing', 'tierverify', 'tier verify']):
            insert_idx = i
            break

    if insert_idx is None:
        insert_idx = len(doc.paragraphs)

    # Check if "Gerelateerde Documenten" already exists
    for p in doc.paragraphs:
        if 'gerelateerde documenten' in p.text.strip().lower():
            # Find the table after this heading and update it, or just add after
            # For simplicity, remove old heading and table (if any) and re-add
            pass

    # We'll insert before the body element at the right position
    # Build heading + table as new elements
    
    # Create heading paragraph
    heading_para = doc.add_paragraph()
    heading_para.style = doc.styles['Heading 1'] if 'Heading 1' in [s.name for s in doc.styles] else doc.styles['Normal']
    run = heading_para.add_run("Gerelateerde Documenten")
    run.bold = True
    run.font.size = Pt(14)
    run.font.color.rgb = RGBColor(0, 0x33, 0x68)

    # Create table
    table = doc.add_table(rows=1, cols=4)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    
    # Header row
    headers = ["Nr", "Document", "Code", "Relatie tot dit document"]
    for j, h in enumerate(headers):
        cell = table.rows[0].cells[j]
        cell.text = ""
        p = cell.paragraphs[0]
        run = p.add_run(h)
        run.bold = True
        run.font.size = Pt(10)
        run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        set_cell_shading(cell, "003368")

    # Data rows
    for ref in ALL_REFS:
        row = table.add_row()
        rel = RELATIONSHIPS[current_doc_nr][ref["nr"]]
        data = [str(ref["nr"]), ref["title"], ref["code"], rel]
        for j, val in enumerate(data):
            cell = row.cells[j]
            cell.text = ""
            p = cell.paragraphs[0]
            run = p.add_run(val)
            run.font.size = Pt(9)
            if j == 3 and rel == "(dit document)":
                run.italic = True
            if ref["nr"] % 2 == 0:
                set_cell_shading(cell, "F2F6FA")

    # Move heading + table to correct position (before bronverwijzingen/tierverify)
    body = doc.element.body
    heading_elem = body[-2]  # second to last (heading)
    table_elem = body[-1]    # last (table)
    
    # Find the element at insert_idx
    all_body_children = list(body)
    
    # Find the paragraph element for insert_idx
    para_elements = [el for el in all_body_children if el.tag == qn('w:p')]
    if insert_idx < len(para_elements):
        target = para_elements[insert_idx]
        body.remove(heading_elem)
        body.remove(table_elem)
        target.addprevious(heading_elem)
        target.addprevious(table_elem)
    
    # Set column widths
    widths = [Cm(1.2), Cm(5.5), Cm(3.0), Cm(7.5)]
    for row in table.rows:
        for j, width in enumerate(widths):
            row.cells[j].width = width


def add_inline_refs(doc, current_doc_nr):
    """Add inline cross-references in the text."""
    # Define per-document search patterns and refs to add
    patterns = []
    
    if current_doc_nr == 1:  # PBZO
        patterns = [
            ("verantwoordelijkheden en bevoegdheden", " (zie PE-310-02, §2)"),
            ("organisatiestructuur", " (zie PE-310-03)"),
            ("veiligheidsrollen", " (zie PE-310-02, §2)"),
            ("competentie", " (zie FM-310-01-01)"),
            ("nieuwe medewerkers", " (zie PE-310-01)"),
        ]
    elif current_doc_nr == 2:  # Functieprofielen
        patterns = [
            ("training", " (zie FM-310-01-01)"),
            ("inwerkprogramma", " (zie PE-310-01)"),
            ("organisatorische structuur", " (zie PE-310-03)"),
            ("beleid", " (zie PS-230)"),
        ]
    elif current_doc_nr == 3:  # Organigram
        patterns = [
            ("functieprofiel", " (zie PE-310-02)"),
            ("beleid", " (zie PS-230)"),
            ("training", " (zie FM-310-01-01)"),
            ("inwerk", " (zie PE-310-01)"),
        ]
    elif current_doc_nr == 4:  # Training Matrix
        patterns = [
            ("inwerkprogramma", " (zie PE-310-01)"),
            ("functieprofiel", " (zie PE-310-02)"),
            ("beleid", " (zie PS-230)"),
            ("organisatiestructuur", " (zie PE-310-03)"),
        ]
    elif current_doc_nr == 5:  # Inwerkprogramma
        patterns = [
            ("functieprofiel", " (zie PE-310-02)"),
            ("organisatiestructuur", " (zie PE-310-03)"),
            ("training", " (zie FM-310-01-01)"),
            ("beleid", " (zie PS-230)"),
        ]
    
    count = 0
    for para in doc.paragraphs:
        # Skip headings and the related docs section itself
        if para.style and 'Heading' in para.style.name:
            continue
        text = para.text.lower()
        
        for search, ref_text in patterns:
            if search.lower() in text:
                # Find the run containing the search text and append ref
                # Simple approach: add to the last run of the paragraph (once per pattern per para)
                if para.runs:
                    last_run = para.runs[-1]
                    if ref_text.strip() not in last_run.text:
                        last_run.text += ref_text
                        count += 1
                        break  # One ref per paragraph max
    
    return count


def process_document(doc_info):
    """Process one document."""
    src = DELIV / doc_info["file"]
    dst = DELIV / doc_info["new"]
    nr = doc_info["nr"]
    
    print(f"\n{'='*60}")
    print(f"Processing Doc {nr}: {doc_info['title']} ({doc_info['code']})")
    print(f"Source: {src.name}")
    print(f"Target: {dst.name}")
    
    # Archive original
    if nr == 1:
        # Archive v1.1 (current source)
        archive_src = DELIV / "PM_VBS01_01_PBZO_Beleidsdocument_v1.1.docx"
        archive_dst = ARCHIVE / "PM_VBS01_01_PBZO_Beleidsdocument_v1.1.docx"
    else:
        archive_src = src
        archive_dst = ARCHIVE / doc_info["file"]
    
    if not archive_dst.exists():
        shutil.copy2(archive_src, archive_dst)
        print(f"  Archived: {archive_dst.name}")
    
    # Open document
    doc = Document(str(src))
    
    # Add inline refs
    ref_count = add_inline_refs(doc, nr)
    print(f"  Inline refs added: {ref_count}")
    
    # Add related docs section
    add_related_docs_section(doc, nr)
    print(f"  Related docs section added")
    
    # Save
    doc.save(str(dst))
    print(f"  Saved: {dst.name}")
    
    return ref_count


def main():
    ARCHIVE.mkdir(parents=True, exist_ok=True)
    
    total_refs = 0
    for doc_info in DOCS:
        refs = process_document(doc_info)
        total_refs += refs
    
    print(f"\n{'='*60}")
    print(f"COMPLETE — {len(DOCS)} documents processed, {total_refs} inline refs added")
    
    # Cleanup old v1.0 for Doc 1 if v1.2 exists
    v12 = DELIV / "PM_VBS01_01_PBZO_Beleidsdocument_v1.2.docx"
    if v12.exists():
        old = DELIV / "PM_VBS01_01_PBZO_Beleidsdocument_v1.0.docx"
        if old.exists() and not (ARCHIVE / old.name).exists():
            shutil.move(str(old), str(ARCHIVE / old.name))
            print(f"  Cleaned up: {old.name} → archive/")


if __name__ == "__main__":
    main()
