#!/usr/bin/env python3
"""
BalticFusion · local development server
Run from the repo root:  python serve.py
Then open:              http://localhost:8000/web/index.html

Inside a container the browser-open is skipped automatically.

Includes a tiny same-origin proxy at /proxy/opensky/states/all that forwards
queries to https://opensky-network.org/api/states/all so the browser can
bypass OpenSky's restrictive CORS policy.
"""
import http.server
import socketserver
import os
import sys
import time
import urllib.parse
import urllib.request
import urllib.error

PORT = int(os.environ.get("PORT", 8000))
OPEN_URL = f"http://localhost:{PORT}/web/index.html"

OPENSKY_BASE = "https://opensky-network.org/api/states/all"
ALLOWED_OSK_PARAMS = {"lamin", "lomin", "lamax", "lomax", "extended"}
_osk_cache = {"ts": 0.0, "body": None, "status": 0, "key": ""}
OSK_CACHE_TTL_S = 10  # don't hammer OpenSky from multiple tabs

class NoCacheHandler(http.server.SimpleHTTPRequestHandler):
    """Serve with no-cache headers so edits reload immediately."""
    def end_headers(self):
        self.send_header("Cache-Control", "no-store, no-cache, must-revalidate")
        super().end_headers()

    def log_message(self, fmt, *args):
        # Suppress tile-server noise; only log page/data requests
        path = args[0] if args else ""
        if ".png" in str(path) or ".ico" in str(path):
            return
        super().log_message(fmt, *args)

    def do_GET(self):
        if self.path.startswith("/proxy/opensky/states/all"):
            self._handle_opensky_proxy()
            return
        super().do_GET()

    def _handle_opensky_proxy(self):
        parsed = urllib.parse.urlsplit(self.path)
        qs = urllib.parse.parse_qsl(parsed.query, keep_blank_values=True)
        safe = [(k, v) for (k, v) in qs if k in ALLOWED_OSK_PARAMS]
        key = urllib.parse.urlencode(sorted(safe))
        now = time.time()
        if _osk_cache["body"] and _osk_cache["key"] == key and (now - _osk_cache["ts"]) < OSK_CACHE_TTL_S:
            body, status = _osk_cache["body"], _osk_cache["status"]
        else:
            url = OPENSKY_BASE + (("?" + key) if key else "")
            req = urllib.request.Request(url, headers={
                "User-Agent": "r-mac-data-scenarios-proxy/1.0",
                "Accept": "application/json",
            })
            try:
                with urllib.request.urlopen(req, timeout=15) as resp:
                    body = resp.read()
                    status = resp.status
            except urllib.error.HTTPError as e:
                body = (e.read() or b'{"error":"upstream"}')
                status = e.code
            except Exception as e:
                body = (b'{"error":"' + str(e).encode("utf-8", "replace") + b'"}')
                status = 502
            _osk_cache.update({"ts": now, "body": body, "status": status, "key": key})
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Cache-Control", "no-store")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    # Must run from repo root so /scenarios/ and /web/ are both reachable
    repo_root = os.path.dirname(os.path.abspath(__file__))
    os.chdir(repo_root)

    # Bind to all interfaces so the container port is reachable from the host
    bind = os.environ.get("BIND", "0.0.0.0")

    with socketserver.TCPServer((bind, PORT), NoCacheHandler) as httpd:
        httpd.allow_reuse_address = True
        print(f"BalticFusion dev server  →  http://{bind}:{PORT}/web/index.html")
        print("Press Ctrl-C to stop.\n")

        # Skip browser-open when running inside a container or CI
        if os.environ.get("NO_BROWSER") != "1" and bind == "0.0.0.0" and sys.stdout.isatty():
            try:
                import webbrowser
                webbrowser.open(OPEN_URL)
            except Exception:
                pass

        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\nServer stopped.")
            sys.exit(0)
