#!/usr/bin/env python3
"""Mock leaderboard server for local testing.

Stores submitted scores in memory, returns rank/total on POST, and serves
the top-N on GET. Sends permissive CORS so the web build can talk to it
from a different port.

Usage:
    ./tools/mock-leaderboard.py           # listens on :8765
    ./tools/mock-leaderboard.py 8080      # custom port
"""
import json
import sys
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs

# In-memory store: {board_name: [score_record, ...]}
SCORES = {}


def _cors(handler):
    handler.send_header("Access-Control-Allow-Origin", "*")
    handler.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
    handler.send_header("Access-Control-Allow-Headers", "Content-Type")


class Handler(BaseHTTPRequestHandler):
    def do_OPTIONS(self):
        self.send_response(204)
        _cors(self)
        self.end_headers()

    def do_GET(self):
        url = urlparse(self.path)
        if url.path != "/api/scores":
            self.send_response(404); _cors(self); self.end_headers(); return
        q = parse_qs(url.query)
        board = (q.get("board") or [""])[0]
        limit = int((q.get("limit") or ["50"])[0])
        rows = sorted(SCORES.get(board, []),
                      key=lambda r: r["score"], reverse=True)[:limit]
        body = json.dumps({
            "board": board,
            "total": len(SCORES.get(board, [])),
            "scores": [
                {"name": r["name"], "score": r["score"],
                 "end_scene": r["end_scene"]}
                for r in rows
            ],
        }).encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        _cors(self)
        self.end_headers()
        self.wfile.write(body)

    def do_POST(self):
        if urlparse(self.path).path != "/api/scores":
            self.send_response(404); _cors(self); self.end_headers(); return
        length = int(self.headers.get("Content-Length", "0"))
        try:
            payload = json.loads(self.rfile.read(length))
        except Exception as e:
            self.send_response(400); _cors(self); self.end_headers()
            self.wfile.write(f"bad json: {e}".encode())
            return
        board = payload.get("board", "")
        SCORES.setdefault(board, []).append(payload)
        # Rank: 1 = best. Sort descending, find position.
        ranked = sorted(SCORES[board], key=lambda r: r["score"], reverse=True)
        # Identify *this* submission by reference equality.
        rank = next((i + 1 for i, r in enumerate(ranked) if r is payload), -1)
        body = json.dumps({"rank": rank, "total": len(SCORES[board])}).encode()
        print(f"[POST] board={board} name={payload.get('name')} "
              f"score={payload.get('score')} -> #{rank}/{len(SCORES[board])}")
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        _cors(self)
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, fmt, *args):
        # Keep the noise down; we print our own line on POST.
        return


def main():
    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8765
    srv = HTTPServer(("127.0.0.1", port), Handler)
    print(f"mock-leaderboard listening on http://127.0.0.1:{port}")
    try:
        srv.serve_forever()
    except KeyboardInterrupt:
        pass


if __name__ == "__main__":
    main()
