import sys, json, os, time, threading, atexit
from datetime import datetime

STATE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "state", "state_live_ineligible.json")
POLL_SECS = 1
FALLBACK_SECS = 30
MAX_POSITIONS = 6
HEADER_HEIGHT = 4 + MAX_POSITIONS * 2  # 1 cornice + 1 titolo + 1 daily + 1 cornice + N×2

IS_TTY = sys.stdout.isatty()
_lock = threading.Lock()

GREEN = "\033[32m"; RED = "\033[31m"; DIM = "\033[2m"; RESET = "\033[0m"

def fmt_price(x):
    a = abs(x)
    if a >= 100:   return f"{x:.2f}"
    if a >= 1:     return f"{x:.4f}"
    return f"{x:.6f}"

def fmt_pnl(pnl):
    color = GREEN if pnl > 0 else RED if pnl < 0 else ""
    sign = "-" if pnl < 0 else ""
    return f"{color}{sign}${abs(pnl):.2f}{RESET if color else ''}"

def render_position_lines(trade):
    e = trade.get("entry", {}) or {}
    r = trade.get("runtime", {}) or {}
    sym = e.get("symbol", "?")
    direction = str(e.get("direction", "?")).upper()
    entry_p = e.get("entry_price"); sl = e.get("sl_price"); tp = e.get("tp_price")
    pnl = r.get("net_profit_usd", 0.0) or 0.0
    prog = r.get("progress_pct", 0.0) or 0.0
    mins = r.get("minutes_open", 0) or 0
    line1 = f"💼 {sym} {direction} | entry: {fmt_price(entry_p)} | SL: {fmt_price(sl)} | TP: {fmt_price(tp)}"
    line2 = f"   P&L: {fmt_pnl(pnl)} | progress: {prog:.0f}% | open: {mins:.0f}min"
    return line1, line2

def build_daily_line(state):
    daily = state.get("daily") or {}
    pnl = daily.get("daily_pnl") or 0.0
    color = GREEN if pnl > 0 else RED if pnl < 0 else ""
    sign = "+" if pnl >= 0 else "-"
    pnl_str = f"{color}{sign}${abs(pnl):.2f}{RESET if color else ''}"
    executed = daily.get("executed_count") or 0
    return f"  Trade: {executed} exec | P&L: {pnl_str}"

def build_header():
    bar = "═" * 70
    lines = [bar]
    try:
        with open(STATE_PATH) as f:
            state = json.load(f)
        trades = list((state.get("active_trades") or {}).values())
    except Exception:
        lines.append(f"  POSIZIONI APERTE   (stato non leggibile)        {datetime.now().strftime('%H:%M:%S')}")
        lines.append(f"  {DIM}Trade: n/d | P&L: n/d{RESET}")
        lines.append(bar)
        while len(lines) < HEADER_HEIGHT: lines.append("")
        return lines[:HEADER_HEIGHT]
    n = len(trades)
    pad = max(1, 40 - len(str(n)))
    lines.append(f"  POSIZIONI APERTE ({n}){' ' * pad}{datetime.now().strftime('%H:%M:%S')}")
    lines.append(build_daily_line(state))
    lines.append(bar)
    shown = trades[:MAX_POSITIONS - 1] if n > MAX_POSITIONS else trades
    for t in shown:
        try:
            l1, l2 = render_position_lines(t)
        except Exception as ex:
            l1, l2 = f"💼 (errore parsing trade: {ex})", ""
        lines.append(l1); lines.append(l2)
    if not trades:
        lines.append(f"  {DIM}(nessuna posizione aperta){RESET}")
    if n > len(shown):
        lines.append(f"  {DIM}+ {n - len(shown)} posizioni non mostrate{RESET}")
    while len(lines) < HEADER_HEIGHT: lines.append("")
    return lines[:HEADER_HEIGHT]

def redraw_header():
    if not IS_TTY: return
    lines = build_header()
    with _lock:
        sys.stdout.write("\033[s")
        for i, ln in enumerate(lines, start=1):
            sys.stdout.write(f"\033[{i};1H\033[2K{ln}")
        sys.stdout.write("\033[u")
        sys.stdout.flush()

def refresh_loop():
    last_mtime = 0.0
    last_redraw = 0.0
    while True:
        time.sleep(POLL_SECS)
        try:
            now = time.time()
            try:
                mtime = os.path.getmtime(STATE_PATH)
            except OSError:
                mtime = last_mtime
            if mtime != last_mtime or (now - last_redraw) >= FALLBACK_SECS:
                last_mtime = mtime
                last_redraw = now
                redraw_header()
        except Exception:
            pass

def setup_tty():
    sys.stdout.write("\033[2J")
    sys.stdout.write(f"\033[{HEADER_HEIGHT + 1};r")
    sys.stdout.write(f"\033[{HEADER_HEIGHT + 1};1H")
    sys.stdout.flush()
    atexit.register(lambda: (sys.stdout.write("\033[r\033[?25h"), sys.stdout.flush()))

def emit(msg):
    with _lock:
        print(msg)

if IS_TTY:
    setup_tty()
    redraw_header()
    threading.Thread(target=refresh_loop, daemon=True).start()

for line in sys.stdin:
    try:
        t = json.loads(line)
        ev = t.get('event',''); sym = t.get('symbol',''); ts = t.get('ts','')[11:19]
        if ev == 'scan_skip':
            reason = t.get('reason',''); regime = t.get('regime') or '-'
            rsi = t.get('rsi'); h1 = t.get('h1_struct') or '-'
            rsi_str = f" RSI={rsi:.1f}" if rsi else ""
            if reason == 'NEWS_BLOCK':
                d = t.get('details', {})
                mins = t.get('minutes_to_event') or d.get('minutes_to_event','?')
                title = t.get('title') or d.get('title','?')
                country = t.get('country') or d.get('country','?')
                emit(f"{ts} 📰 {sym:4} NEWS_BLOCK {country} '{title[:25]}' {mins}min")
            elif reason == 'OUTSIDE_TRADING_HOURS':
                emit(f"{ts} 🕐 {sym:4} OUTSIDE_HOURS")
            else:
                emit(f"{ts} 📊 {sym:4} {regime:12}{rsi_str} {h1} → {reason}")
        elif ev == 'entry_approved':
            emit(f"{ts} ✅ {sym} APPROVED rr={t.get('rr_multiplier_ai')} conf={t.get('confidence')} {t.get('reason','')[:40]}")
            redraw_header()
        elif ev == 'tp_resolved':
            emit(f"{ts} 💰 {sym} TP usd=${t.get('tp_usd_target')} ticks={t.get('tp_ticks_final')} rr={t.get('rr_effective')}")
        elif ev == 'entry_rejected':
            emit(f"{ts} ❌ {sym} REJECTED {t.get('reason','')[:50]}")
        elif ev == 'news_sync':
            emit(f"{ts} 📰 NEWS SYNC ok")
        elif ev == 'position_closed_externally':
            redraw_header()
    except: pass
