#!/usr/bin/env python3
"""
patch_live_quotes.py — adds minute-live quotes to the Daily Forecasts page.

Run AFTER patch_forecast_page.py has been applied.
Save to the project root and run from there:
    cd C:\\Users\\Administrator\\OneDrive\\fx_macro_intraday
    python patch_live_quotes.py

Changes to dashboard_server.py:
  1. Protects /forecast_live.json behind the same token check.
  2. Adds maybe_refresh_live_quotes(): runs update_live_quotes.py about
     once a minute during weekday sessions (non-blocking subprocess).
  3. Calls it from the existing 30-second update loop.

Safety: backup (.bak_livequotes_<timestamp>), exact-match verify,
syntax check, re-runnable (skips applied changes).
"""

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"

LIVE_BLOCK = r'''# ── Live quotes for the Daily Forecasts page (~minute granularity) ───────
LIVE_QUOTES_SCRIPT = BASE_PATH / "src" / "execution" / "update_live_quotes.py"
_live_quotes_lock = threading.Lock()
_live_quotes_last = [0.0]


def maybe_refresh_live_quotes():
    """Runs update_live_quotes.py roughly once a minute during sessions."""
    if not LIVE_QUOTES_SCRIPT.exists():
        return
    if time.time() - _live_quotes_last[0] < 60:
        return
    if _session_now().weekday() >= 5:
        return
    if not _live_quotes_lock.acquire(blocking=False):
        return
    _live_quotes_last[0] = time.time()

    def _run():
        try:
            r = subprocess.run(
                [sys.executable, str(LIVE_QUOTES_SCRIPT)],
                cwd=str(BASE_PATH), stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL, timeout=55,
            )
            if r.returncode != 0:
                print(f"  [quotes] update failed (exit {r.returncode})")
        except Exception as e:
            print(f"  [quotes] update failed: {e}")
        finally:
            _live_quotes_lock.release()

    threading.Thread(target=_run, daemon=True).start()


'''

PATCHES = [
    {
        "label": "protect /forecast_live.json",
        "old": '"/forecast.html", "/forecast_data.json")',
        "new": '"/forecast.html", "/forecast_data.json",\n'
               '                           "/forecast_live.json")',
        "marker": '"/forecast_live.json")',
        "anchor": "_PROTECTED_PREFIXES",
    },
    {
        "label": "live-quotes machinery (once a minute during sessions)",
        "old": 'def main():\n    print("=" * 60)',
        "new": LIVE_BLOCK + 'def main():\n    print("=" * 60)',
        "marker": "def maybe_refresh_live_quotes",
        "anchor": "def main",
    },
    {
        "label": "call maybe_refresh_live_quotes() in the update loop",
        "old": '            maybe_refresh_forecast()\n'
               '            time.sleep(30)',
        "new": '            maybe_refresh_forecast()\n'
               '            maybe_refresh_live_quotes()\n'
               '            time.sleep(30)',
        "marker": "            maybe_refresh_live_quotes()",
        "anchor": "maybe_refresh_forecast",
    },
]


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
    start = max(0, i - 80)
    end = min(len(text), i + 320)
    print("    Exact bytes around anchor (repr):")
    print("    " + repr(text[start:end]))


def main():
    print("=" * 62)
    print("LIVE QUOTES PATCHER")
    print(f"  Root: {ROOT}")
    print("=" * 62)

    if not SERVER.exists():
        sys.exit(f"FAIL: {SERVER} not found — run from the project root.")

    probe = read_raw(SERVER)
    if "def _session_now" not in probe:
        sys.exit("FAIL: forecast-page patch not applied yet — run "
                 "patch_forecast_page.py first.")
    lq = ROOT / "src" / "execution" / "update_live_quotes.py"
    if not lq.exists():
        print("  NOTE: update_live_quotes.py not found yet — save it to "
              "src\\execution\\ before restarting the server.")

    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_livequotes_{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_livequotes 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. Save build_forecast.py (v3), update_live_quotes.py and")
    print("     forecast.html to their locations (overwrite the old ones).")
    print("  2. Rebuild once:  python src\\execution\\build_forecast.py")
    print("  3. Test quotes:   python src\\execution\\update_live_quotes.py")
    print("  4. Restart the dashboard server.")
    print("  5. Hard-refresh the page (Ctrl+F5 on PC / pull-refresh on phone).")
    print("=" * 62)


if __name__ == "__main__":
    main()
