#!/usr/bin/env python3
"""Market Watch Web Portal - Multiplayer GARP Paper Trading."""

import json
import os
import sys
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
from urllib.parse import urlparse, parse_qs

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import game_engine

PORT = 8889
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SCANS_DIR = os.path.join(PROJECT_DIR, "data", "scans")


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    daemon_threads = True


CSS = """:root{--bg-primary:#0d1117;--bg-secondary:#161b22;--bg-tertiary:#21262d;--text-primary:#f0f6fc;--text-secondary:#8b949e;--border-color:#30363d;--accent-blue:#58a6ff;--accent-purple:#bc8cff;--positive-green:#3fb950;--negative-red:#f85149;--gold:#f0c000;--silver:#c0c0c0;--bronze:#cd7f32}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:var(--bg-primary);color:var(--text-primary);line-height:1.5}
a{color:var(--accent-blue);text-decoration:none}a:hover{text-decoration:underline}
.navbar{background:var(--bg-secondary);border-bottom:1px solid var(--border-color);padding:1rem 2rem;display:flex;align-items:center;justify-content:space-between}
.nav-brand{font-size:1.5rem;font-weight:bold;color:var(--accent-blue)}
.nav-links{display:flex;gap:1.5rem}
.nav-links a{color:var(--text-secondary);text-decoration:none;padding:.5rem 1rem;border-radius:6px;transition:all .2s}
.nav-links a:hover{color:var(--text-primary);background:var(--bg-tertiary)}
.nav-links a.active{color:var(--accent-blue);background:var(--bg-tertiary)}
.container{max-width:1400px;margin:0 auto;padding:2rem}
.card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;padding:1.5rem;margin-bottom:1.5rem}
.card h3{color:var(--text-primary);margin-bottom:1rem;font-size:1.1rem}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1.5rem;margin-bottom:2rem}
.metric-large{font-size:2rem;font-weight:bold;margin-bottom:.3rem}
.metric-small{color:var(--text-secondary);font-size:.85rem}
.positive{color:var(--positive-green)!important}.negative{color:var(--negative-red)!important}
table{width:100%;border-collapse:collapse}
th,td{padding:.6rem .8rem;text-align:left;border-bottom:1px solid var(--border-color)}
th{color:var(--text-secondary);font-size:.8rem;text-transform:uppercase}
td{font-size:.9rem}
.rank-1{color:var(--gold);font-weight:bold}.rank-2{color:var(--silver)}.rank-3{color:var(--bronze)}
.btn{display:inline-block;padding:.5rem 1.2rem;background:var(--accent-blue);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:.9rem;text-decoration:none;transition:opacity .2s}
.btn:hover{opacity:.85;text-decoration:none}
.btn-outline{background:transparent;border:1px solid var(--border-color);color:var(--text-primary)}
.btn-outline:hover{border-color:var(--accent-blue)}
.btn-green{background:var(--positive-green)}.btn-red{background:var(--negative-red)}
input,select{background:var(--bg-tertiary);border:1px solid var(--border-color);color:var(--text-primary);padding:.5rem .8rem;border-radius:6px;font-size:.9rem}
.form-row{display:flex;gap:1rem;align-items:end;flex-wrap:wrap;margin-bottom:1rem}
.form-group{display:flex;flex-direction:column;gap:.3rem}
.form-group label{font-size:.8rem;color:var(--text-secondary);text-transform:uppercase}
.badge{display:inline-block;padding:.15rem .5rem;border-radius:4px;font-size:.75rem;font-weight:bold}
.badge-ai{background:var(--accent-purple);color:#fff}
.badge-human{background:var(--accent-blue);color:#fff}
.player-link{color:var(--text-primary);font-weight:500}
@media(max-width:768px){.navbar{flex-direction:column;gap:1rem}.cards{grid-template-columns:1fr}.container{padding:1rem}.form-row{flex-direction:column}}"""


def nav(active=""):
    return f"""<nav class="navbar">
        <a href="/" style="text-decoration:none"><div class="nav-brand">📊 Market Watch</div></a>
        <div class="nav-links">
            <a href="/" class="{'active' if active=='home' else ''}">Games</a>
            <a href="/scans" class="{'active' if active=='scans' else ''}">Scans</a>
        </div></nav>"""


class MarketWatchHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        try:
            parsed = urlparse(self.path)
            path = parsed.path.rstrip("/")
            params = parse_qs(parsed.query)

            if path == "" or path == "/":
                self.serve_home()
            elif path == "/create-game":
                self.serve_create_game()
            elif path.startswith("/game/") and "/player/" in path:
                parts = path.split("/")  # /game/{gid}/player/{user}
                self.serve_player(parts[2], parts[4])
            elif path.startswith("/game/"):
                game_id = path.split("/")[2]
                self.serve_game(game_id)
            elif path == "/scans":
                self.serve_scans()
            # API
            elif path.startswith("/api/games") and len(path.split("/")) == 3:
                self.send_json(game_engine.list_games(active_only=False))
            elif path.startswith("/api/games/") and path.endswith("/leaderboard"):
                gid = path.split("/")[3]
                self.send_json(game_engine.get_leaderboard(gid))
            elif "/portfolio" in path:
                parts = path.split("/")
                self.send_json(game_engine.get_portfolio(parts[3], parts[5]))
            else:
                self.send_error(404)
        except Exception as e:
            self.send_response(500)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(f"<h1>500</h1><pre>{e}</pre>".encode())

    def do_POST(self):
        try:
            content_len = int(self.headers.get("Content-Length", 0))
            body = self.rfile.read(content_len).decode() if content_len else ""
            parsed = urlparse(self.path)
            path = parsed.path.rstrip("/")

            if path == "/api/games":
                data = parse_form(body)
                name = data.get("name", "Untitled Game")
                cash = float(data.get("starting_cash", 100000))
                end_date = data.get("end_date") or None
                gid = game_engine.create_game(name, cash, end_date)
                self.redirect(f"/game/{gid}")

            elif path.endswith("/join"):
                data = parse_form(body)
                parts = path.split("/")
                gid = parts[3]
                username = data.get("username", "").strip().lower()
                if username:
                    game_engine.join_game(gid, username)
                self.redirect(f"/game/{gid}")

            elif path.endswith("/trade"):
                data = parse_form(body)
                parts = path.split("/")
                gid, username = parts[3], parts[5]
                action = data.get("action", "").upper()
                ticker = data.get("ticker", "").upper().strip()
                shares = int(data.get("shares", 0))
                
                if ticker and shares > 0:
                    import yfinance as yf
                    price = yf.Ticker(ticker).info.get("currentPrice") or yf.Ticker(ticker).info.get("regularMarketPrice", 0)
                    if price and price > 0:
                        if action == "BUY":
                            game_engine.buy(gid, username, ticker, shares, price, reason="Manual trade")
                        elif action == "SELL":
                            game_engine.sell(gid, username, ticker, shares, price, reason="Manual trade")
                
                self.redirect(f"/game/{gid}/player/{username}")
            else:
                self.send_error(404)
        except Exception as e:
            self.send_response(500)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(f"<h1>500</h1><pre>{e}</pre>".encode())

    def serve_home(self):
        games = game_engine.list_games(active_only=False)
        rows = ""
        for g in games:
            players = len(g.get("players", []))
            status_badge = '<span class="badge badge-ai">Active</span>' if g["status"] == "active" else '<span class="badge">Ended</span>'
            rows += f"""<tr>
                <td><a href="/game/{g['game_id']}" class="player-link">{g['name']}</a></td>
                <td>{players}</td>
                <td>${g['starting_cash']:,.0f}</td>
                <td>{g['start_date']}</td>
                <td>{g.get('end_date', '—') or '—'}</td>
                <td>{status_badge}</td>
            </tr>"""
        
        html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Market Watch</title><style>{CSS}</style></head><body>
{nav('home')}
<div class="container">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem">
        <h2>🎮 Active Games</h2>
        <a href="/create-game" class="btn">+ New Game</a>
    </div>
    <div class="card">
        <table><thead><tr><th>Game</th><th>Players</th><th>Starting Cash</th><th>Started</th><th>Ends</th><th>Status</th></tr></thead>
        <tbody>{rows if rows else '<tr><td colspan="6" style="text-align:center;color:var(--text-secondary)">No games yet — create one!</td></tr>'}</tbody></table>
    </div>
</div></body></html>"""
        self.send_html(html)

    def serve_create_game(self):
        html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Create Game - Market Watch</title><style>{CSS}</style></head><body>
{nav()}
<div class="container">
    <div class="card">
        <h3>🎮 Create New Game</h3>
        <form method="POST" action="/api/games">
            <div class="form-row">
                <div class="form-group"><label>Game Name</label><input type="text" name="name" placeholder="GARP Challenge" required></div>
                <div class="form-group"><label>Starting Cash ($)</label><input type="number" name="starting_cash" value="100000" min="1000" step="1000"></div>
                <div class="form-group"><label>End Date (optional)</label><input type="date" name="end_date"></div>
            </div>
            <button type="submit" class="btn">Create Game</button>
        </form>
    </div>
</div></body></html>"""
        self.send_html(html)

    def serve_game(self, game_id):
        game = game_engine.get_game(game_id)
        if not game:
            return self.send_error(404)
        
        board = game_engine.get_leaderboard(game_id)
        
        rank_rows = ""
        for i, entry in enumerate(board):
            rank_class = f"rank-{i+1}" if i < 3 else ""
            medal = ["🥇", "🥈", "🥉"][i] if i < 3 else f"#{i+1}"
            pnl_class = "positive" if entry["pnl_pct"] >= 0 else "negative"
            badge = ' <span class="badge badge-ai">AI</span>' if entry["username"] == "case" else ""
            rank_rows += f"""<tr>
                <td class="{rank_class}">{medal}</td>
                <td><a href="/game/{game_id}/player/{entry['username']}" class="player-link">{entry['username']}</a>{badge}</td>
                <td>${entry['total_value']:,.2f}</td>
                <td class="{pnl_class}">{entry['pnl_pct']:+.2f}%</td>
                <td class="{pnl_class}">${entry['total_pnl']:+,.2f}</td>
                <td>{entry['num_positions']}</td>
                <td>{entry['num_trades']}</td>
            </tr>"""

        html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>{game['name']} - Market Watch</title><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>{CSS}</style></head><body>
{nav()}
<div class="container">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem">
        <h2>🏆 {game['name']}</h2>
        <span class="badge badge-ai">{game['status'].upper()}</span>
    </div>
    <p style="color:var(--text-secondary);margin-bottom:1.5rem">Started {game['start_date']} · ${game['starting_cash']:,.0f} starting cash · {len(game['players'])} players</p>
    
    <div class="card">
        <h3>Leaderboard</h3>
        <table><thead><tr><th>Rank</th><th>Player</th><th>Portfolio</th><th>Return</th><th>P&L</th><th>Positions</th><th>Trades</th></tr></thead>
        <tbody>{rank_rows if rank_rows else '<tr><td colspan="7" style="text-align:center;color:var(--text-secondary)">No players yet</td></tr>'}</tbody></table>
    </div>
    
    <div class="card">
        <h3>Join This Game</h3>
        <form method="POST" action="/api/games/{game_id}/join">
            <div class="form-row">
                <div class="form-group"><label>Username</label><input type="text" name="username" placeholder="your name" required pattern="[a-zA-Z0-9_-]+" title="Letters, numbers, dashes, underscores only"></div>
                <button type="submit" class="btn">Join Game</button>
            </div>
        </form>
    </div>
</div></body></html>"""
        self.send_html(html)

    def serve_player(self, game_id, username):
        game = game_engine.get_game(game_id)
        p = game_engine.get_portfolio(game_id, username)
        if not game or not p:
            return self.send_error(404)
        
        trades = game_engine.get_trades(game_id, username)
        snapshots = game_engine.get_snapshots(game_id, username)
        
        pnl_class = "positive" if p["total_pnl"] >= 0 else "negative"
        is_ai = username == "case"
        badge = '<span class="badge badge-ai">AI Player</span>' if is_ai else '<span class="badge badge-human">Human</span>'
        
        # Positions table
        pos_rows = ""
        for ticker, pos in sorted(p["positions"].items()):
            pc = "positive" if pos["unrealized_pnl"] >= 0 else "negative"
            pos_rows += f"""<tr>
                <td><strong>{ticker}</strong></td><td>{pos['shares']}</td>
                <td>${pos['avg_cost']:.2f}</td><td>${pos['current_price']:.2f}</td>
                <td>${pos['market_value']:,.2f}</td><td class="{pc}">${pos['unrealized_pnl']:+,.2f}</td>
                <td>${pos.get('trailing_stop',0):.2f}</td>
            </tr>"""
        if not pos_rows:
            pos_rows = '<tr><td colspan="7" style="text-align:center;color:var(--text-secondary)">No positions</td></tr>'
        
        # Trade log
        trade_rows = ""
        for t in reversed(trades[-30:]):
            action_class = "positive" if t["action"] == "BUY" else "negative"
            pnl_cell = ""
            if t["action"] == "SELL":
                rpnl = t.get("realized_pnl", 0)
                rpnl_class = "positive" if rpnl >= 0 else "negative"
                pnl_cell = f'<span class="{rpnl_class}">${rpnl:+,.2f}</span>'
            trade_rows += f"""<tr>
                <td class="{action_class}">{t['action']}</td><td>{t['ticker']}</td><td>{t['shares']}</td>
                <td>${t['price']:.2f}</td><td>{pnl_cell}</td>
                <td>{t.get('reason','')[:40]}</td><td>{t['timestamp'][:16]}</td>
            </tr>"""
        
        chart_labels = json.dumps([s["date"] for s in snapshots])
        chart_values = json.dumps([s["total_value"] for s in snapshots])
        starting = game.get("starting_cash", 100000)
        
        # Trade form (only for humans)
        trade_form = "" if is_ai else f"""
        <div class="card">
            <h3>📝 Place Trade</h3>
            <form method="POST" action="/api/games/{game_id}/players/{username}/trade">
                <div class="form-row">
                    <div class="form-group"><label>Action</label>
                        <select name="action"><option value="BUY">BUY</option><option value="SELL">SELL</option></select></div>
                    <div class="form-group"><label>Ticker</label><input type="text" name="ticker" placeholder="AAPL" required style="text-transform:uppercase"></div>
                    <div class="form-group"><label>Shares</label><input type="number" name="shares" min="1" value="10" required></div>
                    <button type="submit" class="btn btn-green">Execute</button>
                </div>
                <p style="color:var(--text-secondary);font-size:.8rem;margin-top:.5rem">Trades execute at current market price via Yahoo Finance</p>
            </form>
        </div>"""

        html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>{username} - {game['name']}</title><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>{CSS}</style></head><body>
{nav()}
<div class="container">
    <div style="margin-bottom:.5rem"><a href="/game/{game_id}" style="color:var(--text-secondary)">← {game['name']}</a></div>
    <h2>{username} {badge}</h2>
    <div class="cards" style="margin-top:1rem">
        <div class="card"><h3>Portfolio Value</h3><div class="metric-large">${p['total_value']:,.2f}</div><div class="metric-small">Started at ${starting:,.0f}</div></div>
        <div class="card"><h3>Cash</h3><div class="metric-large">${p['cash']:,.2f}</div><div class="metric-small">{p['cash']/max(p['total_value'],1)*100:.1f}% available</div></div>
        <div class="card"><h3>Return</h3><div class="metric-large {pnl_class}">{p['pnl_pct']:+.2f}%</div><div class="metric-small {pnl_class}">${p['total_pnl']:+,.2f}</div></div>
        <div class="card"><h3>Positions</h3><div class="metric-large">{p['num_positions']}</div><div class="metric-small">{len(trades)} total trades</div></div>
    </div>
    
    <div class="card"><h3>Performance</h3><canvas id="chart" height="80"></canvas></div>
    
    {trade_form}
    
    <div class="card"><h3>Positions</h3>
        <table><thead><tr><th>Ticker</th><th>Shares</th><th>Avg Cost</th><th>Price</th><th>Value</th><th>P&L</th><th>Stop</th></tr></thead>
        <tbody>{pos_rows}</tbody></table>
    </div>
    
    <div class="card"><h3>Trade Log</h3>
        <table><thead><tr><th>Action</th><th>Ticker</th><th>Shares</th><th>Price</th><th>P&L</th><th>Reason</th><th>Time</th></tr></thead>
        <tbody>{trade_rows if trade_rows else '<tr><td colspan="7" style="text-align:center;color:var(--text-secondary)">No trades yet</td></tr>'}</tbody></table>
    </div>
</div>
<script>
const ctx = document.getElementById('chart').getContext('2d');
const labels = {chart_labels}; const values = {chart_values};
if (labels.length > 0) {{
    new Chart(ctx, {{type:'line',data:{{labels:labels,datasets:[
        {{label:'Portfolio',data:values,borderColor:'#58a6ff',backgroundColor:'rgba(88,166,255,0.1)',fill:true,tension:0.3}},
        {{label:'Starting',data:labels.map(()=>{starting}),borderColor:'#30363d',borderDash:[5,5],pointRadius:0}}
    ]}},options:{{responsive:true,plugins:{{legend:{{labels:{{color:'#f0f6fc'}}}}}},scales:{{x:{{ticks:{{color:'#8b949e'}},grid:{{color:'#21262d'}}}},y:{{ticks:{{color:'#8b949e',callback:v=>'$'+v.toLocaleString()}},grid:{{color:'#21262d'}}}}}}}}
    }});
}} else {{ ctx.canvas.parentElement.innerHTML += '<div style="text-align:center;color:#8b949e;padding:2rem">Chart populates after first trading day</div>'; }}
</script></body></html>"""
        self.send_html(html)

    def serve_scans(self):
        rows = ""
        if os.path.exists(SCANS_DIR):
            for sf in sorted(os.listdir(SCANS_DIR), reverse=True)[:30]:
                if not sf.endswith(".json"): continue
                data = {}
                with open(os.path.join(SCANS_DIR, sf)) as f:
                    data = json.load(f)
                n = data.get("candidates_found", len(data.get("candidates", [])))
                top = ", ".join(c.get("ticker","?") for c in data.get("candidates", [])[:8])
                rows += f'<tr><td>{sf.replace(".json","")}</td><td>{data.get("total_scanned",0)}</td><td>{n}</td><td>{top or "—"}</td></tr>'

        html = f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Scans - Market Watch</title><style>{CSS}</style></head><body>
{nav('scans')}
<div class="container"><div class="card"><h3>📡 GARP Scan History</h3>
    <table><thead><tr><th>Date</th><th>Scanned</th><th>Candidates</th><th>Top Picks</th></tr></thead>
    <tbody>{rows if rows else '<tr><td colspan="4" style="text-align:center;color:var(--text-secondary)">No scans yet</td></tr>'}</tbody></table>
</div></div></body></html>"""
        self.send_html(html)

    def redirect(self, url):
        self.send_response(303)
        self.send_header("Location", url)
        self.end_headers()

    def send_html(self, content):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(content.encode())

    def send_json(self, data):
        self.send_response(200)
        self.send_header("Content-type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        self.wfile.write(json.dumps(data, default=str).encode())

    def log_message(self, format, *args):
        pass


def parse_form(body):
    """Parse URL-encoded form data."""
    result = {}
    for pair in body.split("&"):
        if "=" in pair:
            k, v = pair.split("=", 1)
            from urllib.parse import unquote_plus
            result[unquote_plus(k)] = unquote_plus(v)
    return result


def main():
    game_engine.ensure_default_game()
    print(f"📊 Market Watch Portal starting on localhost:{PORT}")
    server = ThreadedHTTPServer(("0.0.0.0", PORT), MarketWatchHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nPortal stopped")


if __name__ == "__main__":
    main()
