#!/usr/bin/env python3
"""
Paper trading simulator for Feed Hunter strategies.

Tracks virtual positions, P&L, and performance metrics.
No real money — everything is simulated.

Usage:
    python3 simulator.py status                          # Show all active sims
    python3 simulator.py open <strategy> <details_json>  # Open a paper position
    python3 simulator.py close <sim_id> <exit_price>     # Close a position
    python3 simulator.py update <sim_id> <current_price> # Update mark-to-market
    python3 simulator.py history                         # Show closed positions
    python3 simulator.py stats                           # Performance summary
"""

import argparse
import json
import os
import sys
import uuid
from datetime import datetime, timezone
from pathlib import Path

DATA_DIR = Path(__file__).parent / "data" / "simulations"
ACTIVE_FILE = DATA_DIR / "active.json"
HISTORY_FILE = DATA_DIR / "history.json"
CONFIG_FILE = Path(__file__).parent / "config.json"


def load_config():
    with open(CONFIG_FILE) as f:
        return json.load(f)


def load_active():
    if ACTIVE_FILE.exists():
        with open(ACTIVE_FILE) as f:
            return json.load(f)
    return {"positions": [], "bankroll_used": 0}


def save_active(data):
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    with open(ACTIVE_FILE, "w") as f:
        json.dump(data, f, indent=2)


def load_history():
    if HISTORY_FILE.exists():
        with open(HISTORY_FILE) as f:
            return json.load(f)
    return {"closed": []}


def save_history(data):
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    with open(HISTORY_FILE, "w") as f:
        json.dump(data, f, indent=2)


def cmd_open(args):
    """Open a new paper position."""
    config = load_config()
    sim_config = config["simulation"]
    active = load_active()
    
    details = json.loads(args.details)
    
    # Calculate position size
    bankroll = sim_config["default_bankroll"]
    max_pos = bankroll * sim_config["max_position_pct"]
    position_size = details.get("size", max_pos)
    position_size = min(position_size, max_pos)
    
    sim_id = str(uuid.uuid4())[:8]
    
    position = {
        "id": sim_id,
        "strategy": args.strategy,
        "opened_at": datetime.now(timezone.utc).isoformat(),
        "type": details.get("type", "long"),  # long, short, bet
        "asset": details.get("asset", "unknown"),
        "entry_price": details.get("entry_price", 0),
        "size": position_size,
        "quantity": details.get("quantity", 0),
        "stop_loss": details.get("stop_loss"),
        "take_profit": details.get("take_profit"),
        "current_price": details.get("entry_price", 0),
        "unrealized_pnl": 0,
        "unrealized_pnl_pct": 0,
        "source_post": details.get("source_post", ""),
        "thesis": details.get("thesis", ""),
        "notes": details.get("notes", ""),
        "updates": [],
    }
    
    active["positions"].append(position)
    active["bankroll_used"] = sum(p["size"] for p in active["positions"])
    save_active(active)
    
    print(f"✅ Paper position opened: {sim_id}")
    print(f"   Strategy: {args.strategy}")
    print(f"   Asset: {position['asset']}")
    print(f"   Type: {position['type']}")
    print(f"   Entry: ${position['entry_price']}")
    print(f"   Size: ${position_size:.2f}")
    if position["stop_loss"]:
        print(f"   Stop Loss: ${position['stop_loss']}")
    if position["take_profit"]:
        print(f"   Take Profit: ${position['take_profit']}")


def cmd_close(args):
    """Close a paper position."""
    active = load_active()
    history = load_history()
    
    pos = None
    for i, p in enumerate(active["positions"]):
        if p["id"] == args.sim_id:
            pos = active["positions"].pop(i)
            break
    
    if not pos:
        print(f"❌ Position {args.sim_id} not found")
        sys.exit(1)
    
    exit_price = float(args.exit_price)
    entry_price = pos["entry_price"]
    
    if pos["type"] == "long":
        pnl_pct = (exit_price - entry_price) / entry_price if entry_price else 0
    elif pos["type"] == "short":
        pnl_pct = (entry_price - exit_price) / entry_price if entry_price else 0
    elif pos["type"] == "bet":
        # For binary bets: exit_price is 1 (win) or 0 (lose)
        pnl_pct = (exit_price - entry_price) / entry_price if entry_price else 0
    else:
        pnl_pct = 0
    
    realized_pnl = pos["size"] * pnl_pct
    
    pos["closed_at"] = datetime.now(timezone.utc).isoformat()
    pos["exit_price"] = exit_price
    pos["realized_pnl"] = round(realized_pnl, 2)
    pos["realized_pnl_pct"] = round(pnl_pct * 100, 2)
    
    history["closed"].append(pos)
    active["bankroll_used"] = sum(p["size"] for p in active["positions"])
    
    save_active(active)
    save_history(history)
    
    emoji = "🟢" if realized_pnl >= 0 else "🔴"
    print(f"{emoji} Position closed: {pos['id']}")
    print(f"   Asset: {pos['asset']}")
    print(f"   Entry: ${entry_price} → Exit: ${exit_price}")
    print(f"   P&L: ${realized_pnl:+.2f} ({pnl_pct*100:+.1f}%)")


def cmd_update(args):
    """Update mark-to-market for a position."""
    active = load_active()
    
    for pos in active["positions"]:
        if pos["id"] == args.sim_id:
            current = float(args.current_price)
            entry = pos["entry_price"]
            
            if pos["type"] == "long":
                pnl_pct = (current - entry) / entry if entry else 0
            elif pos["type"] == "short":
                pnl_pct = (entry - current) / entry if entry else 0
            else:
                pnl_pct = (current - entry) / entry if entry else 0
            
            pos["current_price"] = current
            pos["unrealized_pnl"] = round(pos["size"] * pnl_pct, 2)
            pos["unrealized_pnl_pct"] = round(pnl_pct * 100, 2)
            pos["updates"].append({
                "time": datetime.now(timezone.utc).isoformat(),
                "price": current,
                "pnl": pos["unrealized_pnl"],
            })
            
            # Check stop loss
            if pos.get("stop_loss") and pos["type"] == "long" and current <= pos["stop_loss"]:
                print(f"⚠️  STOP LOSS triggered for {pos['id']} at ${current}")
            if pos.get("take_profit") and pos["type"] == "long" and current >= pos["take_profit"]:
                print(f"🎯 TAKE PROFIT hit for {pos['id']} at ${current}")
            
            save_active(active)
            
            emoji = "🟢" if pos["unrealized_pnl"] >= 0 else "🔴"
            print(f"{emoji} Updated {pos['id']}: ${current} ({pos['unrealized_pnl_pct']:+.1f}%)")
            return
    
    print(f"❌ Position {args.sim_id} not found")


def cmd_status(args):
    """Show all active positions."""
    active = load_active()
    config = load_config()
    bankroll = config["simulation"]["default_bankroll"]
    
    if not active["positions"]:
        print("No active paper positions.")
        return
    
    total_unrealized = 0
    print(f"=== Active Paper Positions ===")
    print(f"Bankroll: ${bankroll} | Used: ${active['bankroll_used']:.2f} | Free: ${bankroll - active['bankroll_used']:.2f}\n")
    
    for pos in active["positions"]:
        emoji = "🟢" if pos["unrealized_pnl"] >= 0 else "🔴"
        total_unrealized += pos["unrealized_pnl"]
        print(f"{emoji} [{pos['id']}] {pos['strategy']}")
        print(f"   {pos['asset']} | {pos['type']} | Size: ${pos['size']:.2f}")
        print(f"   Entry: ${pos['entry_price']} → Current: ${pos['current_price']}")
        print(f"   P&L: ${pos['unrealized_pnl']:+.2f} ({pos['unrealized_pnl_pct']:+.1f}%)")
        print(f"   Opened: {pos['opened_at'][:16]}")
        if pos.get("thesis"):
            print(f"   Thesis: {pos['thesis'][:80]}")
        print()
    
    print(f"Total unrealized P&L: ${total_unrealized:+.2f}")


def cmd_history(args):
    """Show closed positions."""
    history = load_history()
    
    if not history["closed"]:
        print("No closed positions yet.")
        return
    
    print("=== Closed Positions ===\n")
    for pos in history["closed"]:
        emoji = "🟢" if pos["realized_pnl"] >= 0 else "🔴"
        print(f"{emoji} [{pos['id']}] {pos['strategy']}")
        print(f"   {pos['asset']} | ${pos['entry_price']} → ${pos['exit_price']}")
        print(f"   P&L: ${pos['realized_pnl']:+.2f} ({pos['realized_pnl_pct']:+.1f}%)")
        print(f"   {pos['opened_at'][:16]} → {pos['closed_at'][:16]}")
        print()


def cmd_stats(args):
    """Performance summary across all closed trades."""
    history = load_history()
    config = load_config()
    
    closed = history.get("closed", [])
    if not closed:
        print("No completed trades to analyze.")
        return
    
    wins = [t for t in closed if t["realized_pnl"] > 0]
    losses = [t for t in closed if t["realized_pnl"] <= 0]
    total_pnl = sum(t["realized_pnl"] for t in closed)
    
    print("=== Performance Summary ===\n")
    print(f"Total trades: {len(closed)}")
    print(f"Wins: {len(wins)} | Losses: {len(losses)}")
    print(f"Win rate: {len(wins)/len(closed)*100:.1f}%")
    print(f"Total P&L: ${total_pnl:+.2f}")
    
    if wins:
        avg_win = sum(t["realized_pnl"] for t in wins) / len(wins)
        best = max(closed, key=lambda t: t["realized_pnl"])
        print(f"Avg win: ${avg_win:+.2f}")
        print(f"Best trade: {best['id']} ({best['strategy']}) ${best['realized_pnl']:+.2f}")
    
    if losses:
        avg_loss = sum(t["realized_pnl"] for t in losses) / len(losses)
        worst = min(closed, key=lambda t: t["realized_pnl"])
        print(f"Avg loss: ${avg_loss:+.2f}")
        print(f"Worst trade: {worst['id']} ({worst['strategy']}) ${worst['realized_pnl']:+.2f}")
    
    # ROI
    bankroll = config["simulation"]["default_bankroll"]
    roi = (total_pnl / bankroll) * 100
    print(f"\nROI on ${bankroll} bankroll: {roi:+.1f}%")
    
    # By strategy
    strategies = {}
    for t in closed:
        s = t["strategy"]
        if s not in strategies:
            strategies[s] = {"trades": 0, "pnl": 0, "wins": 0}
        strategies[s]["trades"] += 1
        strategies[s]["pnl"] += t["realized_pnl"]
        if t["realized_pnl"] > 0:
            strategies[s]["wins"] += 1
    
    if len(strategies) > 1:
        print(f"\n=== By Strategy ===")
        for name, data in sorted(strategies.items(), key=lambda x: x[1]["pnl"], reverse=True):
            wr = data["wins"] / data["trades"] * 100
            print(f"  {name}: {data['trades']} trades, {wr:.0f}% WR, ${data['pnl']:+.2f}")


def main():
    parser = argparse.ArgumentParser(description="Feed Hunter Paper Trading Simulator")
    sub = parser.add_subparsers(dest="command")
    
    sub.add_parser("status", help="Show active positions")
    
    p_open = sub.add_parser("open", help="Open paper position")
    p_open.add_argument("strategy", help="Strategy name")
    p_open.add_argument("details", help="JSON with position details")
    
    p_close = sub.add_parser("close", help="Close position")
    p_close.add_argument("sim_id", help="Position ID")
    p_close.add_argument("exit_price", help="Exit price")
    
    p_update = sub.add_parser("update", help="Update mark-to-market")
    p_update.add_argument("sim_id", help="Position ID")
    p_update.add_argument("current_price", help="Current price")
    
    sub.add_parser("history", help="Closed positions")
    sub.add_parser("stats", help="Performance summary")
    
    args = parser.parse_args()
    
    if args.command == "status":
        cmd_status(args)
    elif args.command == "open":
        cmd_open(args)
    elif args.command == "close":
        cmd_close(args)
    elif args.command == "update":
        cmd_update(args)
    elif args.command == "history":
        cmd_history(args)
    elif args.command == "stats":
        cmd_stats(args)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
