from __future__ import annotations

import argparse
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import Any

from kernite.evaluator import evaluate_execute


def _json_response(handler: BaseHTTPRequestHandler, status: int, body: dict[str, Any]) -> None:
    encoded = json.dumps(body, ensure_ascii=False).encode("utf-8")
    handler.send_response(status)
    handler.send_header("Content-Type", "application/json; charset=utf-8")
    handler.send_header("Content-Length", str(len(encoded)))
    handler.end_headers()
    handler.wfile.write(encoded)


class _GovernanceHandler(BaseHTTPRequestHandler):
    def log_message(self, fmt: str, *args: Any) -> None:
        return

    def do_GET(self) -> None:
        if self.path == "/health":
            _json_response(self, 200, {"status": "ok"})
            return
        _json_response(self, 404, {"message": "Not found"})

    def do_POST(self) -> None:
        if self.path not in ("/execute", "/v1/execute"):
            _json_response(self, 404, {"message": "Not found"})
            return

        length_header = self.headers.get("Content-Length") or "0"
        try:
            length = int(length_header)
        except ValueError:
            _json_response(self, 400, {"message": "Invalid Content-Length"})
            return

        raw = self.rfile.read(length) if length > 0 else b"{}"
        try:
            body = json.loads(raw.decode("utf-8"))
        except json.JSONDecodeError:
            _json_response(self, 400, {"message": "Invalid JSON payload"})
            return

        if not isinstance(body, dict):
            _json_response(self, 400, {"message": "Request body must be an object"})
            return

        idempotency_key = self.headers.get("Idempotency-Key")
        result = evaluate_execute(body, idempotency_key=idempotency_key)
        _json_response(self, 200, result)


def _serve(host: str, port: int) -> None:
    server = ThreadingHTTPServer((host, port), _GovernanceHandler)
    print(f"kernite serving on http://{host}:{port}", flush=True)
    server.serve_forever()


def main() -> None:
    parser = argparse.ArgumentParser(prog="kernite")
    subparsers = parser.add_subparsers(dest="command")

    serve_parser = subparsers.add_parser("serve", help="Start reference governance API server")
    serve_parser.add_argument("--host", default="127.0.0.1", help="Host to bind (default: 127.0.0.1)")
    serve_parser.add_argument("--port", default=8000, type=int, help="Port to bind (default: 8000)")

    args = parser.parse_args()

    if args.command == "serve":
        _serve(args.host, args.port)
        return

    parser.print_help()


if __name__ == "__main__":
    main()
