#!/usr/bin/env python3
"""
patch_v3_dealquery_bug.py  (v2 - dash-free matching)
====================================================
ROOT-CAUSE FIX for the recurring UNKNOWN / Pending P&L bug.

THE BUG:
  _get_closed_pnl() used mt5.history_deals_get(start, now) - a date-range
  query - which does NOT reliably return recently-created exit deals on the
  IC Markets demo broker. mt5.history_deals_get(position=ticket) does.

PROOF (trade #1675593149, 2026-06-01):
  date-range query found 1 of 2 deals; position query found both (+$407.51).

This v2 matches on short, dash-free text fragments to avoid em-dash
encoding mismatches that caused v1 to abort.

Usage:  python patch_v3_dealquery_bug.py
"""
import sys, shutil, ast
from pathlib import Path

candidates = [
    Path(r"C:\Users\paul_\OneDrive\fx_macro_intraday\src\execution\live_signal_monitor_v3.py"),
    Path(r"C:\Users\Administrator\OneDrive\fx_macro_intraday\src\execution\live_signal_monitor_v3.py"),
    Path(__file__).parent / "live_signal_monitor_v3.py",
]
target = next((p for p in candidates if p.exists()), None)
if target is None:
    print("ERROR: could not find live_signal_monitor_v3.py")
    sys.exit(1)
print(f"Target file: {target}")

backup = target.with_suffix(".py.backup_dealquery2")
if not backup.exists():
    shutil.copy2(target, backup)
    print(f"Backup created: {backup}")
else:
    print(f"Backup already exists: {backup}")

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

# PATCH 1 - match only dash-free lines
old1 = """        for attempt in range(1, max_attempts + 1):
            deals = mt5.history_deals_get(start, now)
            if deals is None:"""

new1 = """        for attempt in range(1, max_attempts + 1):
            # ROOT-CAUSE FIX (2026-06-01): query by POSITION first. The
            # date-range query is unreliable on IC Markets demo and omits
            # recent exit deals; the position query returns them reliably.
            deals = mt5.history_deals_get(position=ticket)
            if not deals:
                deals = mt5.history_deals_get(start, now)
            if deals is None:"""

count1 = content.count(old1)
if count1 == 1:
    content = content.replace(old1, new1)
    print("PATCH 1 applied: _get_closed_pnl queries by position first")
elif new1 in content:
    print("PATCH 1 skipped: already applied")
elif count1 == 0:
    print("ERROR: PATCH 1 anchor not found. Aborting, no changes written.")
    sys.exit(2)
else:
    print(f"ERROR: PATCH 1 anchor found {count1} times (expected 1). Aborting.")
    sys.exit(2)

# PATCH 2 - reconcile heal fallback
old2 = """                mt5_net_pnl = sum(d.profit + d.swap + d.commission
                                  for d in pair_deals)

                if int(pos_id) in existing_tickets:"""

new2 = """                mt5_net_pnl = sum(d.profit + d.swap + d.commission
                                  for d in pair_deals)

                # If date-range scan only saw the entry deal (IC Markets
                # quirk, see 2026-06-01 root cause), try the position query
                # which reliably returns the exit deal.
                if len([d for d in pair_deals if getattr(d, "entry", None) == 1]) == 0:
                    pos_specific = mt5.history_deals_get(position=int(pos_id))
                    if pos_specific and len(pos_specific) > len(pair_deals):
                        mt5_net_pnl = sum(d.profit + d.swap + d.commission
                                          for d in pos_specific)
                        pair_deals = sorted(pos_specific, key=lambda d: d.time)

                if int(pos_id) in existing_tickets:"""

count2 = content.count(old2)
if count2 == 1:
    content = content.replace(old2, new2)
    print("PATCH 2 applied: reconcile heal uses position query fallback")
elif new2 in content:
    print("PATCH 2 skipped: already applied")
elif count2 == 0:
    print("WARNING: PATCH 2 anchor not found - reconcile heal NOT patched.")
    print("  PATCH 1 still applies (fixes all FUTURE closes).")
else:
    print(f"WARNING: PATCH 2 anchor found {count2} times - skipping to be safe.")

try:
    ast.parse(content)
    print("Syntax check: OK")
except SyntaxError as e:
    print(f"ERROR: syntax error after patch: {e}. Aborting, no changes written.")
    sys.exit(3)

target.write_text(content, encoding="utf-8")
print(f"\nSUCCESS: patched {target}")
print("\nNext steps:")
print("  1. Restart v3 (Ctrl+C, up arrow, Enter).")
print("  2. Watch startup log for:")
print("     [RECONCILE-HEAL] EURUSD ticket 1675593149 ... +407.51 ... corrected")
print("  3. All future closes capture P&L on first attempt.")
