"""cortex/cli/server_cmds.py — serve, dashboard, mcp."""
from __future__ import annotations

import http.server
import logging
import os
import sys
import urllib.error
import urllib.request
from pathlib import Path

import click

import cortex.cli.app as _app

main = _app.main
logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# evaos serve
# ---------------------------------------------------------------------------

@main.command("serve")
@click.option(
    "--host",
    default=lambda: os.environ.get("CORTEX_HOST", "127.0.0.1"),
    show_default="127.0.0.1 (or $CORTEX_HOST)",
    help="Bind host.",
)
@click.option(
    "--port",
    default=lambda: os.environ.get("CORTEX_PORT", "8420"),
    show_default="8420 (or $CORTEX_PORT)",
    type=int,
    help="Bind port.",
)
@click.pass_context
def cmd_serve(ctx: click.Context, host: str, port: int) -> None:
    """Start the Cortex HTTP API server.

    Requires: fastapi, uvicorn (install with: pip install evaos[api])
    """
    try:
        import uvicorn  # noqa: F401
    except ImportError:
        _app._err("uvicorn is not installed. Run: pip install 'evaos[api]'")
        sys.exit(1)

    try:
        from cortex.api.http_server import create_app
    except ImportError as exc:
        _app._err(f"Cannot import HTTP server: {exc}")
        sys.exit(1)

    db_path = ctx.obj["db"]
    config_path = ctx.obj["config"]

    # Inject DB path via environment for the HTTP server
    if db_path:
        os.environ.setdefault("CORTEX_DB_PATH", db_path)
    if config_path:
        os.environ.setdefault("CORTEX_CONFIG_PATH", config_path)

    _app._ok(f"Starting Cortex HTTP API on http://{host}:{port}")
    import uvicorn
    app = create_app(config_path=config_path, db_path=db_path)
    uvicorn.run(app, host=host, port=port)


# ---------------------------------------------------------------------------
# evaos dashboard
# ---------------------------------------------------------------------------

@main.command("dashboard")
@click.option("--port", default=8421, show_default=True, help="Dashboard port.")
@click.option(
    "--api-url",
    default="http://localhost:8420",
    show_default=True,
    help="evaOS API server URL to proxy /api/ requests to.",
)
@click.pass_context
def cmd_dashboard(ctx: click.Context, port: int, api_url: str) -> None:
    """Serve the evaOS dashboard UI with API proxy.

    Starts a static file server for the dashboard/ directory and proxies
    /api/ requests to the main evaOS API server (avoids CORS issues).

    Usage: evaos dashboard --port 8421 --api-url http://localhost:8420
    """
    dashboard_dir = Path(__file__).resolve().parent.parent.parent / "dashboard"
    if not dashboard_dir.is_dir():
        _app._err(f"Dashboard directory not found: {dashboard_dir}")
        sys.exit(1)

    api_url_clean = api_url.rstrip("/")

    class DashboardHandler(http.server.SimpleHTTPRequestHandler):
        """Serves static files from dashboard/ and proxies /api/ to evaOS."""

        def __init__(self, *args, **kwargs):
            super().__init__(*args, directory=str(dashboard_dir), **kwargs)

        def do_GET(self):
            if self.path.startswith("/api/"):
                self._proxy()
            else:
                super().do_GET()

        def do_POST(self):
            self._proxy()

        def do_PUT(self):
            self._proxy()

        def do_PATCH(self):
            self._proxy()

        def do_DELETE(self):
            self._proxy()

        def _proxy(self):
            target = f"{api_url_clean}{self.path}"
            body = None
            content_length = int(self.headers.get("Content-Length", 0))
            if content_length > 0:
                body = self.rfile.read(content_length)

            # Forward headers (except Host)
            headers = {}
            for key in self.headers:
                if key.lower() != "host":
                    headers[key] = self.headers[key]

            try:
                req = urllib.request.Request(
                    target,
                    data=body,
                    headers=headers,
                    method=self.command,
                )
                with urllib.request.urlopen(req, timeout=30) as resp:
                    self.send_response(resp.status)
                    for k, v in resp.getheaders():
                        if k.lower() not in ("transfer-encoding",):
                            self.send_header(k, v)
                    self.end_headers()
                    self.wfile.write(resp.read())
            except urllib.error.HTTPError as e:
                self.send_response(e.code)
                self.send_header("Content-Type", "application/json")
                self.end_headers()
                self.wfile.write(e.read())
            except Exception as e:
                self.send_response(502)
                self.send_header("Content-Type", "text/plain")
                self.end_headers()
                self.wfile.write(f"Proxy error: {e}".encode())

        def log_message(self, format, *args):
            logger.info(format % args)

    _app._ok(f"evaOS Dashboard: http://localhost:{port}")
    _app._ok(f"API proxy → {api_url_clean}")
    server = http.server.HTTPServer(("0.0.0.0", port), DashboardHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        _app._ok("Dashboard stopped.")
        server.server_close()


# ---------------------------------------------------------------------------
# evaos mcp
# ---------------------------------------------------------------------------

@main.command("mcp")
@click.pass_context
def cmd_mcp(ctx: click.Context) -> None:
    """Start the Cortex MCP server (stdio transport).

    Requires: mcp (install with: pip install evaos[mcp])
    """
    try:
        from cortex.api.mcp_server import main as mcp_main
    except ImportError as exc:
        _app._err(f"Cannot import MCP server: {exc}")
        _app._err("Run: pip install 'evaos[mcp]'")
        sys.exit(1)

    db_path = ctx.obj["db"]
    config_path = ctx.obj["config"]
    if db_path:
        os.environ.setdefault("CORTEX_DB_PATH", db_path)
    if config_path:
        os.environ.setdefault("CORTEX_CONFIG_PATH", config_path)

    _app._ok("Starting Cortex MCP server (stdio)…")
    mcp_main()
