#!/usr/bin/env python3
"""
Automated Leverage Trader
Runs short scanner + spot scanner, opens positions in the Leverage Challenge game,
manages exits (TP/SL/trailing stop), and reports via Telegram.

Zero AI tokens — systemd timer.
"""

import json
import os
import sys
import time
import urllib.request
from datetime import datetime, timezone
from pathlib import Path

# Add parent to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

from leverage_game import (
    ensure_default_game, get_game, get_portfolio, open_position,
    close_position, update_prices, get_trades, get_leaderboard
)
from scripts.short_scanner import scan_coin, COINS as SHORT_COINS

TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "6443752046")

DATA_DIR = Path(__file__).parent.parent / "data" / "leverage-game"
STATE_FILE = DATA_DIR / "trader_state.json"

# Trading params
MARGIN_PER_TRADE = 200       # $200 margin per position
DEFAULT_LEVERAGE = 10         # 10x default
MAX_OPEN_POSITIONS = 10       # Max simultaneous positions
SHORT_SCORE_THRESHOLD = 50    # Min score to open short
LONG_SCORE_THRESHOLD = 45     # Min score to open long
TP_PCT = 5.0                  # Take profit at 5% on margin (50% on notional at 10x)
SL_PCT = -3.0                 # Stop loss at -3% on margin (30% on notional at 10x)
TRAILING_STOP_PCT = 2.0       # Trailing stop: close if drops 2% from peak


def load_state():
    if STATE_FILE.exists():
        return json.loads(STATE_FILE.read_text())
    return {"peak_pnl": {}, "last_alert": None}

def save_state(state):
    STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    STATE_FILE.write_text(json.dumps(state, indent=2))


def send_telegram(message):
    if not TELEGRAM_BOT_TOKEN:
        print(f"[TG] {message}")
        return
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    data = json.dumps({
        "chat_id": TELEGRAM_CHAT_ID,
        "text": message,
        "parse_mode": "HTML"
    }).encode()
    req = urllib.request.Request(url, data=data, headers={
        "Content-Type": "application/json", "User-Agent": "Mozilla/5.0"
    })
    try:
        urllib.request.urlopen(req, timeout=10)
    except Exception as e:
        print(f"Telegram failed: {e}")


def run_short_scan():
    """Run short scanner on all coins."""
    results = []
    for symbol in SHORT_COINS:
        r = scan_coin(symbol)
        if r:
            r["direction"] = "short"
            results.append(r)
        time.sleep(0.15)
    return sorted(results, key=lambda x: x['score'], reverse=True)


def run_spot_scan():
    """Run spot/long scanner (inverse of short criteria — oversold = buy)."""
    results = []
    for symbol in SHORT_COINS:
        r = scan_coin(symbol)
        if r:
            # Invert: low RSI + below VWAP = long opportunity
            long_score = 0
            reasons = []
            
            if r['rsi'] <= 25:
                long_score += 30
                reasons.append(f"RSI extremely oversold ({r['rsi']})")
            elif r['rsi'] <= 30:
                long_score += 25
                reasons.append(f"RSI oversold ({r['rsi']})")
            elif r['rsi'] <= 35:
                long_score += 15
                reasons.append(f"RSI low ({r['rsi']})")
            elif r['rsi'] <= 40:
                long_score += 5
                reasons.append(f"RSI mildly low ({r['rsi']})")
            
            if r['vwap_pct'] < -5:
                long_score += 20
                reasons.append(f"Well below VWAP ({r['vwap_pct']:+.1f}%)")
            elif r['vwap_pct'] < -3:
                long_score += 15
                reasons.append(f"Below VWAP ({r['vwap_pct']:+.1f}%)")
            elif r['vwap_pct'] < -1:
                long_score += 8
                reasons.append(f"Slightly below VWAP ({r['vwap_pct']:+.1f}%)")
            
            if r['change_24h'] < -15:
                long_score += 15
                reasons.append(f"Dumped {r['change_24h']:.1f}% 24h")
            elif r['change_24h'] < -8:
                long_score += 10
                reasons.append(f"Down {r['change_24h']:.1f}% 24h")
            elif r['change_24h'] < -4:
                long_score += 5
                reasons.append(f"Down {r['change_24h']:.1f}% 24h")
            
            if r['bb_position'] < 0:
                long_score += 15
                reasons.append(f"Below lower Bollinger ({r['bb_position']:.2f})")
            elif r['bb_position'] < 0.15:
                long_score += 10
                reasons.append(f"Near lower Bollinger ({r['bb_position']:.2f})")
            
            results.append({
                "symbol": r["symbol"],
                "price": r["price"],
                "rsi": r["rsi"],
                "vwap_pct": r["vwap_pct"],
                "change_24h": r["change_24h"],
                "bb_position": r["bb_position"],
                "score": long_score,
                "reasons": reasons,
                "direction": "long",
            })
        time.sleep(0.15)
    return sorted(results, key=lambda x: x['score'], reverse=True)


def manage_exits(game_id, username, state):
    """Check open positions for TP/SL/trailing stop exits."""
    pf = get_portfolio(game_id, username)
    if not pf:
        return []
    
    exits = []
    for pos_id, pos in list(pf["positions"].items()):
        pnl_pct = (pos.get("unrealized_pnl", 0) / pos["margin_usd"] * 100) if pos["margin_usd"] > 0 else 0
        
        # Track peak PnL for trailing stop
        peak_key = pos_id
        if peak_key not in state.get("peak_pnl", {}):
            state["peak_pnl"][peak_key] = pnl_pct
        if pnl_pct > state["peak_pnl"].get(peak_key, 0):
            state["peak_pnl"][peak_key] = pnl_pct
        
        peak = state["peak_pnl"].get(peak_key, 0)
        reason = None
        
        # Take profit
        if pnl_pct >= TP_PCT:
            reason = f"TP hit ({pnl_pct:+.1f}%)"
        # Stop loss
        elif pnl_pct <= SL_PCT:
            reason = f"SL hit ({pnl_pct:+.1f}%)"
        # Trailing stop (only if we were profitable)
        elif peak >= 2.0 and (peak - pnl_pct) >= TRAILING_STOP_PCT:
            reason = f"Trailing stop (peak {peak:+.1f}%, now {pnl_pct:+.1f}%)"
        
        if reason:
            result = close_position(game_id, username, pos_id, reason=reason)
            if result.get("success"):
                exits.append(result)
                # Clean up peak tracking
                state["peak_pnl"].pop(peak_key, None)
    
    return exits


def main():
    game_id = ensure_default_game()
    state = load_state()
    
    print(f"=== Leverage Trader ===")
    print(f"Time: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}")
    print(f"Game: {game_id}")
    
    # 1. Update prices and check liquidations
    liquidations = update_prices(game_id, "case")
    for liq in liquidations:
        msg = f"💀 <b>LIQUIDATED</b>: {liq['symbol']} {liq['direction']} {liq.get('leverage', '?')}x | Lost ${abs(liq.get('pnl', 0)):.2f}"
        send_telegram(msg)
        print(msg)
    
    # 2. Manage exits (TP/SL/trailing)
    exits = manage_exits(game_id, "case", state)
    for ex in exits:
        emoji = "✅" if ex.get("pnl", 0) > 0 else "❌"
        msg = (f"{emoji} <b>Closed</b>: {ex['symbol']} {ex['direction']} | "
               f"Entry: ${ex['entry_price']:.4f} → Exit: ${ex['exit_price']:.4f} | "
               f"PnL: ${ex['pnl']:+.2f} ({ex['pnl_pct']:+.1f}%)")
        print(msg)
    
    # 3. Get current portfolio
    pf = get_portfolio(game_id, "case")
    num_open = pf["num_positions"] if pf else 0
    slots = MAX_OPEN_POSITIONS - num_open
    
    print(f"\nPortfolio: ${pf['equity']:,.2f} ({pf['pnl_pct']:+.2f}%) | {num_open} positions | {slots} slots open")
    
    # 4. Scan for new opportunities
    if slots > 0:
        # Run both scanners
        shorts = run_short_scan()
        longs = run_spot_scan()
        
        # Get existing symbols to avoid doubling up
        existing_symbols = set()
        if pf:
            for pos in pf["positions"].values():
                existing_symbols.add(pos["symbol"])
        
        opened = []
        
        # Open short positions
        for r in shorts:
            if slots <= 0:
                break
            if r["score"] < SHORT_SCORE_THRESHOLD:
                break
            if r["symbol"] in existing_symbols:
                continue
            
            lev = 15 if r["score"] >= 70 else 10 if r["score"] >= 60 else 7
            result = open_position(game_id, "case", r["symbol"], "short", MARGIN_PER_TRADE, lev,
                                  reason=f"Short scanner score:{r['score']}")
            if result.get("success"):
                opened.append(result)
                existing_symbols.add(r["symbol"])
                slots -= 1
                time.sleep(0.2)
        
        # Open long positions
        for r in longs:
            if slots <= 0:
                break
            if r["score"] < LONG_SCORE_THRESHOLD:
                break
            if r["symbol"] in existing_symbols:
                continue
            
            lev = 15 if r["score"] >= 70 else 10 if r["score"] >= 60 else 7
            result = open_position(game_id, "case", r["symbol"], "long", MARGIN_PER_TRADE, lev,
                                  reason=f"Long scanner score:{r['score']}")
            if result.get("success"):
                opened.append(result)
                existing_symbols.add(r["symbol"])
                slots -= 1
                time.sleep(0.2)
        
        if opened:
            lines = [f"📊 <b>Opened {len(opened)} positions</b>\n"]
            for o in opened:
                lines.append(f"{'🔴' if o['direction']=='short' else '🟢'} {o['symbol']} {o['direction']} {o['leverage']}x @ ${o['entry_price']:.4f} (${o['margin']:.0f} margin)")
            send_telegram("\n".join(lines))
            print(f"\nOpened {len(opened)} new positions")
    
    # 5. Send periodic summary (every 4 hours)
    if exits or liquidations:
        pf = get_portfolio(game_id, "case")  # Refresh
        msg = (f"📈 <b>Leverage Challenge Update</b>\n"
               f"Equity: ${pf['equity']:,.2f} ({pf['pnl_pct']:+.2f}%)\n"
               f"Positions: {pf['num_positions']} | Cash: ${pf['cash']:,.2f}\n"
               f"Realized PnL: ${pf['realized_pnl']:+,.2f} | Fees: ${pf['total_fees']:,.2f}")
        send_telegram(msg)
    
    save_state(state)
    print("\nDone.")


if __name__ == "__main__":
    main()
