"""
dashboard_server_usdjpy_inline_patch.py
========================================
Adds fetch_usdjpy_yield_data() and parse_usdjpy_trades() INLINE
to dashboard_server.py so no separate import file is needed.

Also fixes write_data() to call these functions directly.

Run on VPS from project root:
  python src\execution\dashboard_server_usdjpy_inline_patch.py
"""

from pathlib import Path
import ast

BASE_PATH   = Path(__file__).resolve().parents[2]
SERVER_FILE = BASE_PATH / "src" / "execution" / "dashboard_server.py"


def patch():
    code = SERVER_FILE.read_text(encoding="utf-8")
    changes = 0

    # ── PATCH A: Add inline USDJPY functions before write_data() ─────────────
    INLINE_FNS = '''

def fetch_usdjpy_yield_data():
    """Compute USDJPY z-score from local rate CSVs (US2Y - JP2Y, z_window=30 daily)."""
    try:
        RATES_DIR = BASE_PATH / "data" / "raw" / "rates"
        HISTORY_DAYS = 60
        Z_WINDOW = 30

        def load_rate(fname, col):
            path = RATES_DIR / fname
            if not path.exists():
                return None
            df = pd.read_csv(path, parse_dates=["date"])
            df.columns = [c.lower() for c in df.columns]
            df[col] = pd.to_numeric(df[col], errors="coerce")
            return df[["date", col]].dropna().sort_values("date")

        us2y = load_rate("us2y.csv", "us2y")
        jp2y = load_rate("jp2y.csv", "jp2y")
        if us2y is None or jp2y is None:
            return {"error": "jp2y.csv not found", "current_z": 0.0}

        rates = pd.merge(us2y, jp2y, on="date", how="outer").sort_values("date")
        rates = rates.set_index("date")
        rates = rates.reindex(
            pd.date_range(rates.index.min(), rates.index.max(), freq="D")
        ).ffill().dropna()
        rates["spread"] = rates["us2y"] - rates["jp2y"]

        rates["z_mean"] = rates["spread"].rolling(Z_WINDOW).mean()
        rates["z_std"]  = rates["spread"].rolling(Z_WINDOW).std()
        rates["zscore"] = (rates["spread"] - rates["z_mean"]) / rates["z_std"]
        rates = rates.dropna(subset=["zscore"])

        recent      = rates.iloc[-HISTORY_DAYS:]
        current_z   = float(recent["zscore"].iloc[-1])
        current_spr = float(recent["spread"].iloc[-1])
        us2y_val    = float(recent["us2y"].iloc[-1])
        jp2y_val    = float(recent["jp2y"].iloc[-1])

        return {
            "current_z":      round(current_z, 4),
            "current_spread": round(current_spr, 4),
            "us2y":           round(us2y_val, 4),
            "jp2y":           round(jp2y_val, 4),
            "threshold":      2.0,
            "signal":         "SIGNAL" if abs(current_z) >= 2.0 else "no signal",
            "direction":      ("LONG"  if current_z >= 2.0 else
                               "SHORT" if current_z <= -2.0 else "NEUTRAL"),
            "z_history": [
                {"date": str(d.date()), "z": round(float(z), 4)}
                for d, z in zip(recent.index, recent["zscore"])
            ],
            "spread_history": [
                {"date": str(d.date()), "spread": round(float(s), 4)}
                for d, s in zip(recent.index, recent["spread"])
            ],
        }
    except Exception as e:
        return {"error": str(e), "current_z": 0.0}


def parse_usdjpy_trades():
    """Read USDJPY trade history from trade_history_usdjpy.json."""
    try:
        path = BASE_PATH / "data" / "logs" / "trade_history_usdjpy.json"
        if not path.exists():
            return {"trade_count": 0, "pnl_total": 0, "win_rate": 0, "trades": []}
        trades    = json.loads(path.read_text(encoding="utf-8"))
        pnl_total = sum(t["net_pnl"] for t in trades)
        wins      = sum(1 for t in trades if t["net_pnl"] > 0)
        win_rate  = round(wins / len(trades) * 100, 1) if trades else 0
        return {
            "trade_count": len(trades),
            "pnl_total":   round(pnl_total, 2),
            "win_rate":    win_rate,
            "wins":        wins,
            "losses":      len(trades) - wins,
            "trades":      trades[-20:],
        }
    except Exception as e:
        return {"trade_count": 0, "pnl_total": 0, "error": str(e)}

'''

    if "def fetch_usdjpy_yield_data" not in code:
        code = code.replace("def write_data():", INLINE_FNS + "def write_data():")
        changes += 1
        print("  ✅ Patch A: Added fetch_usdjpy_yield_data() + parse_usdjpy_trades() inline")
    else:
        print("  ⏭  Patch A: Already applied")

    # ── PATCH B: Update write_data() to call inline functions ────────────────
    old_write = '''        data["yields"] = fetch_yield_data()
        DATA_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
        z   = data["zscore"]
        sig = "SIGNAL" if abs(z) >= 2.75 else "no signal"
        print(f"  [{datetime.now().strftime('%H:%M:%S')}] "
              f"z={z:.3f} | {sig} | "
              f"trades={data['trade_count']} | "
              f"pos={data['position']}")'''

    new_write = '''        data["yields"] = fetch_yield_data()

        # USDJPY data — inline functions, no separate import needed
        data["usdjpy"]        = fetch_usdjpy_yield_data()
        data["usdjpy_trades"] = parse_usdjpy_trades()

        # USDJPY outlook
        try:
            uj_z = float(data["usdjpy"].get("current_z", 0.0)) \\
                   if isinstance(data.get("usdjpy"), dict) else 0.0
            data["usdjpy_outlook"] = get_usdjpy_weekly_outlook(uj_z)
        except Exception:
            data["usdjpy_outlook"] = []

        DATA_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
        z    = data["zscore"]
        uj_z = float(data["usdjpy"].get("current_z", 0.0)) \\
               if isinstance(data.get("usdjpy"), dict) else 0.0
        eu_sig = "SIGNAL" if abs(z)    >= 2.75 else "no signal"
        uj_sig = "SIGNAL" if abs(uj_z) >= 2.00 else "no signal"
        print(f"  [{datetime.now().strftime('%H:%M:%S')}] "
              f"EU z={z:.3f} {eu_sig} | "
              f"UJ z={uj_z:.3f} {uj_sig} | "
              f"trades={data['trade_count']} | "
              f"pos={data['position']}")'''

    # Handle both patched and unpatched versions
    if "USDJPY data" not in code:
        if old_write in code:
            code = code.replace(old_write, new_write)
            changes += 1
            print("  ✅ Patch B: Updated write_data() to call USDJPY functions")
        else:
            # Already has a partial patch from patch 6 — replace that version
            old_partial = '''        data["yields"] = fetch_yield_data()

        # ── USDJPY additions ───────────────────────────────────────────────
        try:
            from execution.dashboard_server_v2_additions import (
                fetch_usdjpy_yield_data, parse_usdjpy_trades,
                combined_portfolio_stats,
            )
            data["usdjpy"]        = fetch_usdjpy_yield_data()
            data["usdjpy_trades"] = parse_usdjpy_trades()
            data["portfolio"]     = combined_portfolio_stats()
        except ImportError:
            pass  # additions file not yet deployed — skip gracefully

        # USDJPY signal outlook
        try:
            uj_z = 0.0
            if isinstance(data.get("usdjpy"), dict):
                uj_z = float(data["usdjpy"].get("current_z", 0.0))
            data["usdjpy_outlook"] = get_usdjpy_weekly_outlook(uj_z)
        except Exception as _e:
            data["usdjpy_outlook"] = []'''
        if old_partial in code:
            code = code.replace(old_partial,
                '''        data["yields"] = fetch_yield_data()

        # USDJPY data — inline functions, no separate import needed
        data["usdjpy"]        = fetch_usdjpy_yield_data()
        data["usdjpy_trades"] = parse_usdjpy_trades()

        # USDJPY outlook
        try:
            uj_z = float(data["usdjpy"].get("current_z", 0.0)) \\
                   if isinstance(data.get("usdjpy"), dict) else 0.0
            data["usdjpy_outlook"] = get_usdjpy_weekly_outlook(uj_z)
        except Exception:
            data["usdjpy_outlook"] = []''')
            changes += 1
            print("  ✅ Patch B: Replaced import-based USDJPY block with inline calls")
        else:
            print("  ⚠️  Patch B: Could not find write_data block — check manually")
    else:
        print("  ⏭  Patch B: Already applied")

    # ── Write + syntax check ──────────────────────────────────────────────────
    if changes > 0:
        try:
            ast.parse(code)
        except SyntaxError as e:
            print(f"  ❌ Syntax error: {e}")
            return False
        SERVER_FILE.write_text(code, encoding="utf-8")
        print(f"\n  ✅ dashboard_server.py patched ({changes} changes)")
        print(f"  Restart dashboard_server.py to apply.")
    else:
        print("\n  ✅ Already fully patched — no changes needed")
    return True


if __name__ == "__main__":
    print("=" * 60)
    print("DASHBOARD SERVER — USDJPY Inline Patch")
    print("=" * 60)
    patch()
