"""Embedded HTTP server for custom POST API routes."""
from __future__ import annotations

import json
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import Any

from TgrEzLi.defaults import MAX_REQUEST_BODY_BYTES
from TgrEzLi.handlers import call_user_function
from TgrEzLi.types import TgArgsData


class ApiServer:
    """Runs a background HTTP server that dispatches POST requests to registered routes."""

    def __init__(
        self,
        logger: Any,
        registry: Any,
        host: str = "localhost",
        port: int = 9999,
        max_body_bytes: int = MAX_REQUEST_BODY_BYTES,
    ) -> None:
        self.logger = logger
        self.registry = registry
        self.host = host
        self.port = port
        self.max_body_bytes = max_body_bytes
        self._server_thread: threading.Thread | None = None
        self._running = False
        self._httpd: HTTPServer | None = None

    def start(self) -> None:
        if self._running:
            self.logger.info("API server is already running.")
            return
        self._running = True
        self._server_thread = threading.Thread(target=self._serve_forever, daemon=True)
        self._server_thread.start()

    def stop(self) -> None:
        if not self._running:
            self.logger.info("API server is not running.")
            return
        self._running = False
        if self._httpd:
            self.logger.info("Shutting down API server...")
            self._httpd.shutdown()
            self._httpd.server_close()
        if self._server_thread and self._server_thread.is_alive():
            self._server_thread.join(timeout=5)
        self.logger.info("API server has been stopped.")

    def _serve_forever(self) -> None:
        server_self = self
        max_body = self.max_body_bytes

        class ReusableHTTPServer(HTTPServer):
            allow_reuse_address = True

        class ApiRequestHandler(BaseHTTPRequestHandler):
            def do_POST(handler_self: BaseHTTPRequestHandler) -> None:
                path = handler_self.path
                try:
                    length = int(handler_self.headers.get("Content-Length", 0))
                except ValueError:
                    length = 0
                if length < 0 or length > max_body:
                    handler_self.send_response(413)
                    handler_self.send_header("Content-Type", "application/json; charset=utf-8")
                    handler_self.end_headers()
                    handler_self.wfile.write(
                        json.dumps({"status": "error", "message": "Invalid or too large body"}).encode("utf-8")
                    )
                    return
                raw_body = handler_self.rfile.read(length) if length > 0 else b""
                try:
                    data = json.loads(raw_body.decode("utf-8")) if raw_body else {}
                except json.JSONDecodeError:
                    handler_self.send_response(400)
                    handler_self.send_header("Content-Type", "application/json; charset=utf-8")
                    handler_self.end_headers()
                    handler_self.wfile.write(
                        json.dumps({"status": "error", "message": "Invalid JSON body"}).encode("utf-8")
                    )
                    return

                route_info = server_self.registry.api_routes.get(path)
                if route_info:
                    func = route_info["func"]
                    tg_args = TgArgsData(data)
                    call_user_function(server_self.logger, func, TgArgs=tg_args)
                    handler_self.send_response(200)
                    handler_self.send_header("Content-Type", "application/json; charset=utf-8")
                    handler_self.end_headers()
                    resp = {"status": "ok", "path": path}
                    handler_self.wfile.write(json.dumps(resp).encode("utf-8"))
                else:
                    handler_self.send_response(404)
                    handler_self.send_header("Content-Type", "application/json; charset=utf-8")
                    handler_self.end_headers()
                    resp = {"status": "error", "message": "Route not found"}
                    handler_self.wfile.write(json.dumps(resp).encode("utf-8"))

            def log_message(self, format: str, *args: object) -> None:
                server_self.logger.debug("%s - %s", self.address_string(), format % args)

        with ReusableHTTPServer((self.host, self.port), ApiRequestHandler) as http_server:
            self.logger.info("API server listening on http://%s:%s", self.host, self.port)
            self._httpd = http_server
            try:
                http_server.serve_forever()
            except Exception as e:
                self.logger.error("API server error: %s", e)
            finally:
                self.logger.info("API server serve_forever has exited.")


__all__ = ["ApiServer"]
