import json
import os
import threading
from datetime import datetime, timezone
from http import HTTPStatus
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from typing import Any

from ai_testing_swarm.reporting.report_writer import (
    MANUAL_PASS_OVERRIDES_FILENAME,
    REPORTS_DIR,
)


_WRITE_LOCK = threading.Lock()


def _read_overrides(path: Path) -> dict[str, dict[str, Any]]:
    if not path.exists():
        return {}
    try:
        raw = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    if not isinstance(raw, dict):
        return {}
    out: dict[str, dict[str, Any]] = {}
    for endpoint, value in raw.items():
        if isinstance(value, dict):
            out[str(endpoint)] = dict(value)
    return out


def _write_overrides(path: Path, payload: dict[str, dict[str, Any]]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp_path = path.with_name(path.name + ".tmp")
    tmp_path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
    os.replace(tmp_path, path)


def _manual_pass_update(path: Path, *, endpoint: str, key: str, enabled: bool, run_time: str = "") -> dict[str, Any]:
    endpoint_name = str(endpoint).strip()
    manual_key = str(key).strip()
    if not endpoint_name or not manual_key:
        raise ValueError("endpoint and key are required")

    with _WRITE_LOCK:
        data = _read_overrides(path)
        endpoint_map = dict(data.get(endpoint_name, {}))

        if enabled:
            endpoint_map[manual_key] = {
                "source": "api",
                "updated_at_utc": datetime.now(timezone.utc).isoformat(),
                "endpoint": endpoint_name,
                "run_time": run_time,
            }
        else:
            endpoint_map.pop(manual_key, None)

        if endpoint_map:
            data[endpoint_name] = endpoint_map
        else:
            data.pop(endpoint_name, None)

        _write_overrides(path, data)
        return {"endpoint": endpoint_name, "key": manual_key, "enabled": enabled, "total_keys": len(endpoint_map)}


def serve_reports(*, host: str = "127.0.0.1", port: int = 8787, reports_dir: Path | None = None) -> None:
    root = Path(reports_dir or REPORTS_DIR).resolve()
    root.mkdir(parents=True, exist_ok=True)
    overrides_path = root / MANUAL_PASS_OVERRIDES_FILENAME
    if not overrides_path.exists():
        _write_overrides(overrides_path, {})

    class Handler(SimpleHTTPRequestHandler):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, directory=str(root), **kwargs)

        def end_headers(self) -> None:
            # Allow report pages opened from file:// or another local origin to call the API.
            self.send_header("Access-Control-Allow-Origin", "*")
            self.send_header("Access-Control-Allow-Methods", "POST, OPTIONS, GET")
            self.send_header("Access-Control-Allow-Headers", "Content-Type")
            super().end_headers()

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

        def do_OPTIONS(self) -> None:  # noqa: N802
            self.send_response(HTTPStatus.NO_CONTENT)
            self.send_header("Content-Length", "0")
            self.end_headers()

        def do_POST(self) -> None:  # noqa: N802
            if self.path.rstrip("/") != "/api/manual-pass":
                self._json(HTTPStatus.NOT_FOUND, {"ok": False, "error": "Not found"})
                return
            try:
                raw_len = int(self.headers.get("Content-Length", "0"))
            except Exception:
                raw_len = 0
            raw = self.rfile.read(raw_len) if raw_len > 0 else b"{}"
            try:
                payload = json.loads(raw.decode("utf-8"))
            except Exception:
                self._json(HTTPStatus.BAD_REQUEST, {"ok": False, "error": "Invalid JSON"})
                return

            try:
                result = _manual_pass_update(
                    overrides_path,
                    endpoint=str(payload.get("endpoint") or ""),
                    key=str(payload.get("key") or ""),
                    enabled=bool(payload.get("enabled")),
                    run_time=str(payload.get("run_time") or ""),
                )
            except ValueError as exc:
                self._json(HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)})
                return
            except Exception as exc:
                self._json(HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)})
                return

            self._json(HTTPStatus.OK, {"ok": True, "result": result, "file": str(overrides_path)})

    server = ThreadingHTTPServer((host, int(port)), Handler)
    print(f"Serving reports at http://{host}:{port}/")
    print(f"Manual pass API: http://{host}:{port}/api/manual-pass")
    print(f"Manual pass file: {overrides_path}")
    server.serve_forever()
