#!/usr/bin/env python3
"""
patch_walls_pdf.py — switches the server's walls watcher to the PDF folder.

Run AFTER patch_walls_page.py (the walls machinery must already be in).
Save to the project root:
    cd C:\\Users\\Administrator\\OneDrive\\fx_macro_intraday
    python patch_walls_pdf.py

Changes to dashboard_server.py:
  1. Adds the WALLS_PDF_DIR constant (oi_pdfs folder).
  2. Replaces _walls_stale(): instead of watching only oi_data.xlsx, it
     fingerprints the top-level PDFs in oi_pdfs\\ (history\\ ignored)
     plus the xlsx, and rebuilds whenever that fingerprint changes —
     matching what the new build_walls.py writes as source_sig.

Safety: backup (.bak_wallspdf_<timestamp>), exact-match verify, syntax
check, re-runnable.
"""

import py_compile
import shutil
import sys
import time
from pathlib import Path

ROOT = Path(__file__).resolve().parent
SERVER = ROOT / "src" / "execution" / "dashboard_server.py"

OLD_CONSTS = '''WALLS_SCRIPT = BASE_PATH / "src" / "execution" / "build_walls.py"
WALLS_XLSX   = BASE_PATH / "oi_data.xlsx"
WALLS_JSON   = BASE_PATH / "walls_data.json"'''

NEW_CONSTS = '''WALLS_SCRIPT = BASE_PATH / "src" / "execution" / "build_walls.py"
WALLS_XLSX   = BASE_PATH / "oi_data.xlsx"
WALLS_PDF_DIR = BASE_PATH / "oi_pdfs"
WALLS_JSON   = BASE_PATH / "walls_data.json"'''

OLD_STALE = '''def _walls_stale():
    """True when oi_data.xlsx is newer than the last parsed build."""
    if not WALLS_SCRIPT.exists() or not WALLS_XLSX.exists():
        return False
    try:
        src_mtime = WALLS_XLSX.stat().st_mtime
    except OSError:
        return False
    if not WALLS_JSON.exists():
        return True
    try:
        with open(WALLS_JSON, encoding="utf-8") as f:
            done = json.load(f).get("source_mtime", 0)
    except Exception:
        return True
    return abs(src_mtime - done) > 1.0'''

NEW_STALE = '''def _walls_signature():
    """Fingerprint of the OI sources: top-level PDFs in oi_pdfs
    (history\\\\ ignored) plus oi_data.xlsx if present. Must match
    what build_walls.py writes as source_sig."""
    parts = []
    try:
        if WALLS_PDF_DIR.is_dir():
            for p in sorted(WALLS_PDF_DIR.glob("*.pdf")):
                try:
                    parts.append(f"{p.name}:{int(p.stat().st_mtime)}")
                except OSError:
                    pass
    except Exception:
        pass
    if WALLS_XLSX.exists():
        try:
            parts.append(f"xlsx:{int(WALLS_XLSX.stat().st_mtime)}")
        except OSError:
            pass
    return "|".join(parts)


def _walls_stale():
    """True when the OI sources changed since the last build."""
    if not WALLS_SCRIPT.exists():
        return False
    sig = _walls_signature()
    if not sig:
        return False
    if not WALLS_JSON.exists():
        return True
    try:
        with open(WALLS_JSON, encoding="utf-8") as f:
            done = json.load(f).get("source_sig", "")
    except Exception:
        return True
    return sig != done'''

PATCHES = [
    {
        "label": "add WALLS_PDF_DIR constant",
        "old": OLD_CONSTS,
        "new": NEW_CONSTS,
        "marker": "WALLS_PDF_DIR = ",
        "anchor": "WALLS_SCRIPT",
    },
    {
        "label": "watch the oi_pdfs folder (source signature)",
        "old": OLD_STALE,
        "new": NEW_STALE,
        "marker": "def _walls_signature",
        "anchor": "def _walls_stale",
    },
]


def read_raw(path):
    with open(path, "r", encoding="utf-8", newline="") as f:
        return f.read()


def write_raw(path, text):
    with open(path, "w", encoding="utf-8", newline="") as f:
        f.write(text)


def dump_region(text, anchor):
    i = text.find(anchor)
    if i == -1:
        print(f"    (anchor {anchor!r} not found either — file layout differs)")
        return
    print("    Exact bytes around anchor (repr):")
    print("    " + repr(text[max(0, i - 80):i + 320]))


def main():
    print("=" * 62)
    print("WALLS PDF-WATCHER PATCHER")
    print(f"  Root: {ROOT}")
    print("=" * 62)

    if not SERVER.exists():
        sys.exit(f"FAIL: {SERVER} not found — run from the project root.")
    if "def maybe_refresh_walls" not in read_raw(SERVER):
        sys.exit("FAIL: walls machinery not present — run "
                 "patch_walls_page.py first.")
    if not (ROOT / "oi_pdfs").is_dir():
        print("  NOTE: oi_pdfs folder not found — create it and drop the "
              "CME PDF exports in.")

    ts = time.strftime("%Y%m%d_%H%M%S")
    failures = 0
    changed = False
    backed_up = False

    for spec in PATCHES:
        print(f"\n[{SERVER.name}] {spec['label']}")
        text = read_raw(SERVER)
        nl = "\r\n" if "\r\n" in text else "\n"
        old = spec["old"].replace("\r\n", "\n").replace("\n", nl)
        new = spec["new"].replace("\r\n", "\n").replace("\n", nl)

        if spec["marker"] in text:
            print("  OK: already patched — skipping.")
            continue
        n = text.count(old)
        if n != 1:
            print(f"  FAIL: expected exactly 1 match, found {n}.")
            dump_region(text, spec["anchor"])
            failures += 1
            continue
        if not backed_up:
            backup = SERVER.with_name(SERVER.name + f".bak_wallspdf_{ts}")
            shutil.copy2(SERVER, backup)
            backed_up = True
            print(f"  Backup: {backup.name}")
        write_raw(SERVER, text.replace(old, new, 1))
        if spec["marker"] not in read_raw(SERVER):
            print("  FAIL: post-write verification failed — check backup.")
            failures += 1
            continue
        print("  Patched OK.")
        changed = True

    if changed:
        try:
            py_compile.compile(str(SERVER), doraise=True)
            print(f"\n[{SERVER.name}] Syntax check OK.")
        except Exception as e:
            print(f"\n[{SERVER.name}] SYNTAX CHECK FAILED: {e}")
            print("  Restore from the .bak_wallspdf file and send me this "
                  "output.")
            failures += 1

    print("\n" + "=" * 62)
    if failures:
        print(f"DONE WITH {failures} FAILURE(S) — send me the full output "
              "above.")
        sys.exit(1)
    print("ALL PATCHES APPLIED.")
    print("Next steps:")
    print("  1. python -m pip install pdfplumber   (one time)")
    print("  2. Overwrite build_walls.py in src\\execution\\ and walls.html "
          "in the root.")
    print("  3. Test once:  python src\\execution\\build_walls.py")
    print("     Expect an OK line per PDF in oi_pdfs\\.")
    print("  4. Restart the dashboard server; hard-refresh the walls page.")
    print("=" * 62)


if __name__ == "__main__":
    main()
