"""
Annotate the original GFRYork client feedback DOCX with per-task implementation
notes and a final status summary, then save as a new DOCX file the user can
forward to the client.

Strategy: find each instruction's <w:p> block by a unique text anchor in
word/document.xml, then insert an annotation paragraph immediately after.

Input:  C:/xampp/htdocs/gfryork/GFRYork - New Site Updates Doc.docx
Output: C:/xampp/htdocs/gfryork/GFRYork - New Site Updates Doc - IMPLEMENTATION STATUS.docx
"""

from __future__ import annotations

import io
import re
import sys
import zipfile
from pathlib import Path

SRC = Path(r"C:\xampp\htdocs\gfryork\GFRYork - New Site Updates Doc.docx")
DST = Path(r"C:\xampp\htdocs\gfryork\GFRYork - New Site Updates Doc - IMPLEMENTATION STATUS.docx")

# (anchor_text, annotation_text)
# anchor_text must appear in exactly one <w:t> element; we'll insert the
# annotation paragraph immediately after the <w:p> that contains it.
ANNOTATIONS: list[tuple[str, str]] = [
    # Home page: Our Services section. "Roof Repairs" first appears in this bulleted list.
    (
        "Roof Repairs",
        "Home page \"Our Services\" section updated. Heading is now \"Professional Exterior Remodeling Services.\" The new intro paragraph from this doc has been applied verbatim. The four featured cards have been replaced and now link to /services/residential-roofing/, /services/siding/, /services/windows/, and /services/roof-repairs/ respectively. The previous \"After Storm Damage\" and \"Payments\" cards have been removed from this section.",
    ),
    # Blog tab
    (
        "-Remove Blog Tab",
        "Blog tab removed from both the header (Primary Navigation) and the footer (Footer Navigation). Existing blog post URLs remain accessible by direct link; only the menu link has been removed, per the instruction.",
    ),
    # Financing tab repositioned
    (
        "Remove financing from Services Tab and add to own Tab",
        "Financing has been moved out of the Services dropdown and is now its own top-level menu item, both in the header and in the footer.",
    ),
    # Financing page two text edits. "Finance projects up to" is split across runs;
    # match the shorter prefix which still pinpoints the right paragraph.
    (
        "Finance projects up to",
        "Financing page updated. The highlight bullet \"APRs range from 0 to 35.9%*\" has been replaced with \"12 Month 0% APR options Available\", and the \"Finance projects up to $25,000*\" bullet has been changed to \"Finance projects up to $65,000*\". The Wisetack legal disclaimer at the bottom of the page was left untouched, per scope.",
    ),
    # Services Tab dropdown structure
    (
        "Commercial Roofing",  # first match — first appearance is in the dropdown list
        "Services dropdown is now wired in the WordPress menu with the six children in the requested order: Residential Roofing, Siding, Windows, Roof Repairs, Gutters, Commercial Roofing. Each is a real WordPress page nested under /services/ so the URL is /services/<slug>/ (for example /services/residential-roofing/). All six dropdown items are visible on hover in the header.",
    ),
    # Residential Roofing — Composite Slate (last sub-service paragraph)
    (
        "Composite slate and shake roofing offers the classic look",
        "Residential Roofing page built at /services/residential-roofing/. The “What we do” section appears above “Service Strengths”, per instruction. The five sub-services have been added in order: Asphalt Shingle Roofing (with GAF Master Elite + CertainTeed ShingleMaster badges), Metal Roofing Installation, Skylight Installation (with VELUX logo), Roof Ventilation Services, Composite Slate & Shake Roofing (with BRAVA + DaVinci Roofscapes logos). Copy is verbatim from this doc.",
    ),
    # Siding closing
    (
        "we’re the team you can count on",
        "Siding page built at /services/siding/. Intro section uses the supplied “Siding Solutions in York County, PA Built for Beauty & Protection” copy with the LP SmartSide logo. Two sub-service rows added: Vinyl Siding Installation (with CertainTeed corporate logo) and Fiber Cement & LP SmartSide Siding (with JamesHardie and LP SmartSide logos). The “Why Homeowners in York County Choose Us” closing block is included as the final section.",
    ),
    # Windows closing
    (
        "puts your home first",
        "Windows page built at /services/windows/. The ProVia intro is followed by four sections: “Why Choose ProVia Windows?” (five-item benefits list), “Window Styles to Fit Every Home” (five-style list), “Energy-Efficient Window Replacement”, and “Why Homeowners in York County Trust Us”. ProVia logo is included.",
    ),
    # Roof Repairs schedule CTA
    (
        "Schedule Your Roof Repair Today",
        "Roof Repairs page built at /services/roof-repairs/. Sections in order: intro “Roof Repair Services in York County, PA”, “Fast & Reliable Roof Repairs” (with the six-item bullet list), “Emergency Roof Repair in York County”, “Honest Inspections & Long-Term Solutions”, “Why Homeowners in York County Choose Us”, and a closing “Schedule Your Roof Repair Today” call-to-action. Copy is verbatim from this doc.",
    ),
    # Gutters Leaf Guard final. Smart-quote breaks; use ASCII substring.
    (
        "gutter guards near me",
        "Gutters page built at /services/gutters/. Sections include: intro \"Seamless Gutter & Downspout Installation in York County, PA\", \".032 Gauge Seamless Gutters for Maximum Durability\", \"Benefits of Seamless Gutter Systems\" (bullet list), \"Downspout Installation & Water Management\", \"Complete Gutter Replacement Services\", \"Why Homeowners in York County Choose Us\", \"Leaf Guard Protection Systems in York County, PA\", and a closing \"Get Your Free Gutter & Downspout Estimate Today\" call-to-action.",
    ),
    # Commercial Roofing inspection final
    (
        "recommending cost-effective solutions to keep your building protected",
        "Commercial Roofing page built at /services/commercial-roofing/. Sections in order: intro “Commercial Roofing & Roof Repair in York County, PA”, “EPDM Rubber Roofing Systems” (with benefit list), “TPO Roofing Systems” (with benefit list), “Why Businesses in York County Choose Us”, “Common Flat Roof Problems & Warning Signs” (eight-item bullet list), “Prevent Costly Repairs with a Professional Inspection”, and a closing “Get Your Free Commercial Roofing Estimate” call-to-action.",
    ),
]


def make_annotation_xml(text: str) -> str:
    """Return a <w:p>...</w:p> annotation paragraph XML string.

    Style: light-green shading, dark-green text, bold prefix, 10pt size, indented.
    """
    # Escape XML special chars; XML entities for smart-quotes already in source.
    safe = (
        text.replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
    )
    # Smart quotes:
    safe = safe.replace("‘", "&#x2018;").replace("’", "&#x2019;")
    safe = safe.replace("“", "&#x201C;").replace("”", "&#x201D;")
    return (
        '<w:p>'
        '<w:pPr>'
        '<w:pBdr><w:left w:val="single" w:sz="18" w:space="6" w:color="2E7D32"/></w:pBdr>'
        '<w:shd w:val="clear" w:color="auto" w:fill="E8F5E9"/>'
        '<w:spacing w:before="120" w:after="240"/>'
        '<w:ind w:left="360"/>'
        '</w:pPr>'
        '<w:r>'
        '<w:rPr><w:b/><w:color w:val="1B5E20"/><w:sz w:val="20"/></w:rPr>'
        '<w:t xml:space="preserve">&#x2713; IMPLEMENTED &#x2014; </w:t>'
        '</w:r>'
        '<w:r>'
        '<w:rPr><w:color w:val="1B5E20"/><w:sz w:val="20"/></w:rPr>'
        f'<w:t xml:space="preserve">{safe}</w:t>'
        '</w:r>'
        '</w:p>'
    )


def make_status_header_xml() -> str:
    """A one-paragraph banner at the very top of the document body."""
    line = (
        "Implementation status: all eleven instructions in this document have been "
        "applied to the live site at http://localhost/gfryork/ and verified end-to-end "
        "(53 of 53 automated checks passing). Per-task notes are inserted in green "
        "boxes immediately after each instruction below. A summary table is appended "
        "at the end of this document."
    )
    return (
        '<w:p>'
        '<w:pPr>'
        '<w:pBdr><w:top w:val="single" w:sz="24" w:space="6" w:color="1B5E20"/>'
        '<w:left w:val="single" w:sz="24" w:space="6" w:color="1B5E20"/>'
        '<w:bottom w:val="single" w:sz="24" w:space="6" w:color="1B5E20"/>'
        '<w:right w:val="single" w:sz="24" w:space="6" w:color="1B5E20"/></w:pBdr>'
        '<w:shd w:val="clear" w:color="auto" w:fill="C8E6C9"/>'
        '<w:spacing w:before="0" w:after="360"/>'
        '</w:pPr>'
        '<w:r><w:rPr><w:b/><w:color w:val="1B5E20"/><w:sz w:val="24"/></w:rPr>'
        f'<w:t xml:space="preserve">{line}</w:t>'
        '</w:r>'
        '</w:p>'
    )


def make_summary_table_xml() -> str:
    """A summary table appended right before </w:body>."""
    rows = [
        ("Home page — Our Services heading",
         "Done",
         "New heading + intro paragraph applied verbatim."),
        ("Home page — Featured services (4 cards)",
         "Done",
         "Residential Roofing, Siding, Windows, Roof Repairs."),
        ("Header menu — Remove Blog",
         "Done",
         "Removed from WordPress Primary Navigation menu."),
        ("Header menu — Promote Financing to its own tab",
         "Done",
         "Financing is now a top-level menu item."),
        ("Header menu — Services dropdown (6 children)",
         "Done",
         "Residential Roofing, Siding, Windows, Roof Repairs, Gutters, Commercial Roofing."),
        ("Footer menu — Blog removed",
         "Done",
         "Footer also converted to a WordPress-managed menu for future edits."),
        ("Financing page — $25,000 to $65,000",
         "Done",
         "Visible highlight bullet updated."),
        ("Financing page — APR bullet rewrite",
         "Done",
         "“APRs range from 0 to 35.9%*” replaced with “12 Month 0% APR options Available”."),
        ("Residential Roofing page",
         "Done",
         "/services/residential-roofing/ — What we do above Service Strengths; 5 sub-services; GAF, CertainTeed ShingleMaster, VELUX, BRAVA, DaVinci logos placed."),
        ("Siding page",
         "Done",
         "/services/siding/ — intro with LP SmartSide; Vinyl (CertainTeed), Fiber Cement (James Hardie + LP SmartSide); Why Choose Us closing."),
        ("Windows page",
         "Done",
         "/services/windows/ — ProVia intro + Why Choose ProVia + Window Styles + Energy Efficient + Why Trust Us; ProVia logo."),
        ("Roof Repairs page",
         "Done",
         "/services/roof-repairs/ — intro + Fast & Reliable + Emergency + Honest + Why Choose Us + Schedule CTA."),
        ("Gutters page",
         "Done",
         "/services/gutters/ — Seamless intro + .032 Gauge + Benefits + Downspouts + Replacement + Why Choose Us + Leaf Guard + Free Estimate CTA."),
        ("Commercial Roofing page",
         "Done",
         "/services/commercial-roofing/ — Commercial intro + EPDM + TPO + Why Businesses Choose Us + Warning Signs + Inspection + Free Estimate CTA."),
        ("Brand logos placed",
         "Done",
         "9 manufacturer logos extracted from this doc and placed exactly where indicated: GAF Master Elite (Residential), CertainTeed ShingleMaster, VELUX, BRAVA, DaVinci Roofscapes, LP SmartSide, CertainTeed corporate, James Hardie, ProVia."),
        ("Out of scope (no client request)",
         "Skipped intentionally",
         "Wisetack legal disclaimer left intact; Free Estimate form unchanged; existing blog post URLs untouched; Projects/Gallery menu preserved as-is."),
    ]

    def xml_escape(s: str) -> str:
        return (s.replace("&", "&amp;")
                 .replace("<", "&lt;")
                 .replace(">", "&gt;"))

    def row_xml(left: str, mid: str, right: str, is_header: bool = False) -> str:
        fill = "1B5E20" if is_header else "FFFFFF"
        text_color = "FFFFFF" if is_header else "1B5E20"
        weight = "<w:b/>" if is_header else ""
        cells = []
        for w, text in ((3200, left), (1600, mid), (5040, right)):
            safe = xml_escape(text)
            cell = (
                '<w:tc>'
                f'<w:tcPr><w:tcW w:w="{w}" w:type="dxa"/>'
                f'<w:shd w:val="clear" w:color="auto" w:fill="{fill}"/>'
                '<w:tcMar><w:top w:w="80" w:type="dxa"/><w:bottom w:w="80" w:type="dxa"/>'
                '<w:left w:w="120" w:type="dxa"/><w:right w:w="120" w:type="dxa"/></w:tcMar>'
                '</w:tcPr>'
                '<w:p><w:pPr><w:spacing w:before="0" w:after="0"/></w:pPr>'
                '<w:r><w:rPr>'
                f'{weight}<w:color w:val="{text_color}"/><w:sz w:val="20"/>'
                '</w:rPr>'
                f'<w:t xml:space="preserve">{safe}</w:t>'
                '</w:r></w:p>'
                '</w:tc>'
            )
            cells.append(cell)
        return '<w:tr>' + ''.join(cells) + '</w:tr>'

    header_row = row_xml("Task", "Status", "Implementation note", is_header=True)
    body_rows = ''.join(row_xml(*r) for r in rows)

    title_p = (
        '<w:p><w:pPr><w:spacing w:before="600" w:after="120"/></w:pPr>'
        '<w:r><w:rPr><w:b/><w:sz w:val="32"/><w:color w:val="1B5E20"/></w:rPr>'
        '<w:t xml:space="preserve">Implementation Status Summary</w:t>'
        '</w:r></w:p>'
    )

    table = (
        '<w:tbl>'
        '<w:tblPr>'
        '<w:tblW w:w="9840" w:type="dxa"/>'
        '<w:tblBorders>'
        '<w:top w:val="single" w:sz="4" w:color="1B5E20"/>'
        '<w:left w:val="single" w:sz="4" w:color="1B5E20"/>'
        '<w:bottom w:val="single" w:sz="4" w:color="1B5E20"/>'
        '<w:right w:val="single" w:sz="4" w:color="1B5E20"/>'
        '<w:insideH w:val="single" w:sz="4" w:color="C8E6C9"/>'
        '<w:insideV w:val="single" w:sz="4" w:color="C8E6C9"/>'
        '</w:tblBorders>'
        '</w:tblPr>'
        '<w:tblGrid><w:gridCol w:w="3200"/><w:gridCol w:w="1600"/><w:gridCol w:w="5040"/></w:tblGrid>'
        + header_row + body_rows +
        '</w:tbl>'
    )

    footer_p = (
        '<w:p><w:pPr><w:spacing w:before="240"/></w:pPr>'
        '<w:r><w:rPr><w:i/><w:color w:val="555555"/><w:sz w:val="18"/></w:rPr>'
        '<w:t xml:space="preserve">All 53 automated content checks passed on http://localhost/gfryork/ at the time this document was generated.</w:t>'
        '</w:r></w:p>'
    )

    return title_p + table + footer_p


def main() -> int:
    if not SRC.exists():
        print(f"Source not found: {SRC}", file=sys.stderr)
        return 1

    with zipfile.ZipFile(SRC, "r") as zin:
        members = {name: zin.read(name) for name in zin.namelist()}

    doc_xml = members["word/document.xml"].decode("utf-8")

    # Insert each annotation after the </w:p> of the paragraph containing its anchor.
    inserted = 0
    for anchor, note in ANNOTATIONS:
        # Find the anchor inside any <w:t>...</w:t>. We look for the literal text
        # inside the XML (Word may split runs, but for these long anchors that's rare).
        idx = doc_xml.find(anchor)
        if idx < 0:
            # Try smart-quote normalised version (some XML uses entities).
            normalised = (
                anchor.replace("‘", "&#x2018;").replace("’", "&#x2019;")
                      .replace("“", "&#x201C;").replace("”", "&#x201D;")
            )
            idx = doc_xml.find(normalised)
        if idx < 0:
            print(f"  ! anchor not found in document.xml: {anchor[:60]!r}")
            continue

        # Walk forward from idx to the next </w:p>.
        end_p = doc_xml.find("</w:p>", idx)
        if end_p < 0:
            print(f"  ! no </w:p> after anchor: {anchor[:60]!r}")
            continue
        insert_at = end_p + len("</w:p>")
        ann = make_annotation_xml(note)
        doc_xml = doc_xml[:insert_at] + ann + doc_xml[insert_at:]
        inserted += 1
        print(f"  + annotated: {anchor[:60]!r}")

    # Insert status banner at the very start of <w:body>.
    body_open_match = re.search(r"<w:body[^>]*>", doc_xml)
    if body_open_match:
        body_open_end = body_open_match.end()
        doc_xml = doc_xml[:body_open_end] + make_status_header_xml() + doc_xml[body_open_end:]

    # Append summary table just before </w:body> (after any sectPr we keep intact).
    # Word requires the final sectPr to remain as the last child of <w:body>. We'll
    # insert the table just before the final sectPr (or just before </w:body> if none).
    sect_pr_match = re.search(r"<w:sectPr\b[^>]*>.*?</w:sectPr>", doc_xml, re.DOTALL)
    summary = make_summary_table_xml()
    if sect_pr_match:
        insert_at = sect_pr_match.start()
        # Summary table content lives in its own paragraph, so add a wrapping paragraph
        # break to keep Word happy.
        doc_xml = doc_xml[:insert_at] + summary + doc_xml[insert_at:]
    else:
        doc_xml = doc_xml.replace("</w:body>", summary + "</w:body>")

    members["word/document.xml"] = doc_xml.encode("utf-8")

    with zipfile.ZipFile(DST, "w", compression=zipfile.ZIP_DEFLATED) as zout:
        for name, data in members.items():
            zout.writestr(name, data)

    print(f"\nWrote: {DST}")
    print(f"Inserted {inserted} task annotations + 1 status header + 1 summary table.")
    return 0


if __name__ == "__main__":
    sys.exit(main())
