#!/usr/bin/env python3
"""
patch_fred_cache_fix.py
=======================
Fixes the FRED cache: original only cached SUCCESSES, so a persistent 429
retried every cycle and never let the rolling rate limit clear. New logic
records the ATTEMPT (success or failure) once per day, so FRED is called at
most once per series per day regardless of outcome. On failure the caller's
existing stale-CSV fallback handles display.
"""
import sys, shutil, ast
from pathlib import Path

candidates=[
    Path(r"C:\Users\Administrator\OneDrive\fx_macro_intraday\src\execution\dashboard_server.py"),
    Path(r"C:\Users\paul_\OneDrive\fx_macro_intraday\src\execution\dashboard_server.py"),
]
target=next((c for c in candidates if c.exists()), None)
if target is None: print("ERROR: not found"); sys.exit(1)
print(f"Target: {target}")
shutil.copy2(target, target.with_suffix(".py.backup_fredcachefix"))

src=target.read_text(encoding="utf-8")

# Replace the whole _fred_cached function body. Match from its def to the
# blank line before 'def fetch_yield_data():' (the cache block sits right
# before fetch_yield_data).
import re
# The cache dict line + the function, up to (not incl) 'def fetch_yield_data():'
pattern = re.compile(
    r'# Daily cache for FRED.*?def fetch_yield_data\(\):',
    re.DOTALL)
m = pattern.search(src)
if not m:
    print("ERROR: could not locate the cache block to replace.")
    print("Has the first patch been applied? Looking for marker...")
    if "_fred_daily_cache" not in src:
        print("No _fred_daily_cache found - first patch missing.")
    sys.exit(2)

new_block = '''# Daily cache for FRED SOFR/EFFR (daily banking-day series; 1 attempt/day).
# Records the ATTEMPT even on failure, so a persistent 429 does NOT retry every
# cycle (which previously prevented the rolling rate limit from ever clearing).
_fred_daily_cache = {"date": None,
                     "SOFR": (None, None), "EFFR": (None, None),
                     "SOFR_tried": False, "EFFR_tried": False}
def _fred_cached(series_id, csv_path, fetch_fn):
    """Fetch a FRED series at most ONCE per calendar day, success or fail.
    Returns (value, date) - may be (None, None) if today's single attempt
    failed, in which case the caller falls back to the cached CSV."""
    import datetime as _dt
    today = _dt.datetime.now().date()
    if _fred_daily_cache["date"] != today:
        _fred_daily_cache["date"] = today
        _fred_daily_cache["SOFR"] = (None, None)
        _fred_daily_cache["EFFR"] = (None, None)
        _fred_daily_cache["SOFR_tried"] = False
        _fred_daily_cache["EFFR_tried"] = False
    tried_key = series_id + "_tried"
    # Already attempted today (success or fail) -> return whatever we have,
    # do NOT call FRED again today.
    if _fred_daily_cache.get(tried_key):
        return _fred_daily_cache.get(series_id, (None, None))
    # First attempt today
    _fred_daily_cache[tried_key] = True
    val, vdate = fetch_fn(series_id, csv_path)
    _fred_daily_cache[series_id] = (val, vdate)
    return (val, vdate)

def fetch_yield_data():'''

src = src[:m.start()] + new_block + src[m.end():]

try:
    ast.parse(src); print("Syntax: OK")
except SyntaxError as e:
    print(f"SYNTAX ERROR: {e} -- not writing"); sys.exit(4)

target.write_text(src, encoding="utf-8")
print("Cache logic replaced: now 1 attempt/day even on failure.")
print("SUCCESS - restart the dashboard server.")
print("\\nNOTE: residual 429s may persist for ~1-2 min after restart while")
print("FRED's rolling limit clears. After that, at most 2 FRED calls/day total.")
