"""Local HTTP server that serves the dashboard and proxies API requests."""

from __future__ import annotations

import http.server
import json
import socket
from pathlib import Path
from typing import Any

import httpx

STATIC_DIR = Path(__file__).parent / "static"


class DashboardHandler(http.server.BaseHTTPRequestHandler):
    """HTTP handler that serves dashboard HTML and proxies /api/* to Manta API."""

    api_url: str = ""
    auth_token: str = ""

    def log_message(self, format: str, *args: Any) -> None:  # noqa: A002
        """Suppress default request logging."""

    def do_GET(self) -> None:
        if self.path == "/" or self.path == "/index.html":
            self._serve_html()
        elif self.path.startswith("/api/"):
            self._proxy("GET")
        else:
            self._send_error(404, "Not Found")

    def do_POST(self) -> None:
        if self.path.startswith("/api/"):
            self._proxy("POST")
        else:
            self._send_error(404, "Not Found")

    def do_PUT(self) -> None:
        if self.path.startswith("/api/"):
            self._proxy("PUT")
        else:
            self._send_error(404, "Not Found")

    def do_DELETE(self) -> None:
        if self.path.startswith("/api/"):
            self._proxy("DELETE")
        else:
            self._send_error(404, "Not Found")

    def _serve_html(self) -> None:
        """Serve the dashboard HTML file."""
        html_path = STATIC_DIR / "index.html"
        if not html_path.exists():
            self._send_error(500, "Dashboard HTML not found")
            return

        content = html_path.read_bytes()
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()
        self.wfile.write(content)

    def _proxy(self, method: str) -> None:
        """Proxy request to Manta API with JWT auth."""
        url = f"{self.api_url}{self.path}"
        headers = {"Authorization": f"Bearer {self.auth_token}"}

        # Forward Content-Type from client request
        content_type_req = self.headers.get("Content-Type")
        if content_type_req:
            headers["Content-Type"] = content_type_req

        body = None
        content_length = self.headers.get("Content-Length")
        if content_length:
            body = self.rfile.read(int(content_length))

        try:
            with httpx.Client(timeout=30.0, proxy=None) as client:
                response = client.request(
                    method=method,
                    url=url,
                    headers=headers,
                    content=body,
                )

            # If login succeeded, update server's auth token
            if self.path.startswith("/api/v1/auth/login") and response.status_code == 200:
                try:
                    resp_json = response.json()
                    data = resp_json.get("data", {})
                    if resp_json.get("code") == 200 and data.get("access_token"):
                        DashboardHandler.auth_token = data["access_token"]
                except Exception:
                    pass

            content_type = response.headers.get("content-type", "application/json")
            self.send_response(response.status_code)
            self.send_header("Content-Type", content_type)
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            self.wfile.write(response.content)
        except httpx.ConnectError:
            self._send_json_error(502, "Cannot connect to Manta API")
        except httpx.TimeoutException:
            self._send_json_error(504, "Manta API request timed out")
        except Exception as e:
            self._send_json_error(500, str(e))

    def _send_error(self, code: int, message: str) -> None:
        self.send_response(code)
        self.send_header("Content-Type", "text/plain")
        self.end_headers()
        self.wfile.write(message.encode())

    def _send_json_error(self, code: int, message: str) -> None:
        body = json.dumps({"code": code, "msg": message}).encode()
        self.send_response(code)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(body)


def find_available_port(start: int = 8050, max_tries: int = 20) -> int:
    """Find an available port starting from the given port."""
    for offset in range(max_tries):
        port = start + offset
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            try:
                s.bind(("127.0.0.1", port))
                return port
            except OSError:
                continue
    raise RuntimeError(f"No available port found in range {start}-{start + max_tries - 1}")


def run_server(
    api_url: str,
    auth_token: str,
    port: int = 8050,
    auto_find_port: bool = True,
) -> tuple[http.server.HTTPServer, int]:
    """Create and return the dashboard HTTP server.

    Args:
        api_url: Manta API base URL
        auth_token: JWT access token
        port: Preferred port number
        auto_find_port: If True, find next available port when preferred is taken

    Returns:
        Tuple of (server instance, actual port)
    """
    if auto_find_port:
        port = find_available_port(port)

    DashboardHandler.api_url = api_url.rstrip("/")
    DashboardHandler.auth_token = auth_token

    server = http.server.HTTPServer(("127.0.0.1", port), DashboardHandler)
    return server, port
