"""Dashboard backend — aiohttp server serving the React SPA and API routes."""

from __future__ import annotations

import asyncio
import signal
import tomllib
from pathlib import Path

from aiohttp import web

from hatchdx.dashboard.api.agent_api import agent_routes
from hatchdx.dashboard.api.eval_api import eval_routes
from hatchdx.dashboard.api.server_api import server_routes
from hatchdx.dashboard.api.analytics_api import analytics_routes
from hatchdx.dashboard.api.validate_api import validate_routes
from hatchdx.utils.workspace import find_workspace

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


def create_app() -> web.Application:
    """Create and configure the aiohttp application."""
    app = web.Application()

    # Workspace detection — store on app for handlers to use
    app["workspace_root"] = find_workspace()

    # CORS middleware for development (Vite dev server on :5173)
    app.middlewares.append(cors_middleware)

    # API routes
    app.router.add_routes(agent_routes)
    app.router.add_routes(eval_routes)
    app.router.add_routes(server_routes)
    app.router.add_routes(analytics_routes)
    app.router.add_routes(validate_routes)

    # Overview + health
    app.router.add_get("/api/overview", overview_handler)
    app.router.add_get("/api/health", health_check)

    # Static files + SPA fallback
    if STATIC_DIR.exists():
        app.router.add_static("/assets", STATIC_DIR / "assets", name="assets")
        app.router.add_get("/{path:.*}", spa_fallback)
    else:
        app.router.add_get("/{path:.*}", dev_mode_fallback)

    return app


@web.middleware
async def cors_middleware(
    request: web.Request, handler: web.RequestHandler
) -> web.StreamResponse:
    """Add CORS headers for development."""
    if request.method == "OPTIONS":
        response = web.Response()
    else:
        response = await handler(request)

    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
    response.headers["Access-Control-Allow-Headers"] = "Content-Type"
    return response


async def overview_handler(request: web.Request) -> web.Response:
    """Aggregate overview data for the dashboard home page."""
    from hatchdx.dashboard.api.eval_api import _get_recent_runs
    from hatchdx.dashboard.api.server_api import _get_server_config

    workspace_root: Path | None = request.app["workspace_root"]

    # Project name: read from hdx-workspace.toml if in workspace
    project_name = "hatchdx"
    if workspace_root is not None:
        ws_toml = workspace_root / "hdx-workspace.toml"
        if ws_toml.is_file():
            try:
                with open(ws_toml, "rb") as f:
                    ws_data = tomllib.load(f)
                project_name = ws_data.get("workspace", {}).get("name", project_name)
            except Exception:
                pass

    # Server count
    servers = _get_server_config(workspace_root=workspace_root)
    server_count = len(servers)

    recent_runs = _get_recent_runs(limit=5, workspace_root=workspace_root)

    return web.json_response({
        "project_name": project_name,
        "server_count": server_count,
        "tool_count": 0,
        "recent_runs": recent_runs,
        "servers": list(servers.keys()),
    })


async def health_check(_request: web.Request) -> web.Response:
    return web.json_response({"status": "ok"})


async def spa_fallback(_request: web.Request) -> web.StreamResponse:
    """Serve index.html for all non-API routes (SPA client-side routing)."""
    index = STATIC_DIR / "index.html"
    if index.exists():
        return web.FileResponse(index)
    return web.Response(text="Dashboard not built. Run: cd dashboard && npm run build && npm run copy", status=503)


async def dev_mode_fallback(_request: web.Request) -> web.Response:
    return web.json_response(
        {
            "error": "Dashboard not built",
            "hint": "Run: cd dashboard && npm run build && npm run copy",
            "dev_hint": "Or run 'npm run dev' in dashboard/ and visit http://localhost:5173",
        },
        status=503,
    )


async def run_server(port: int = 4320, open_browser: bool = True) -> None:
    """Start the dashboard server."""
    app = create_app()
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, "localhost", port)

    loop = asyncio.get_event_loop()
    stop_event = asyncio.Event()

    def _signal_handler() -> None:
        stop_event.set()

    for sig in (signal.SIGINT, signal.SIGTERM):
        loop.add_signal_handler(sig, _signal_handler)

    await site.start()

    url = f"http://localhost:{port}"
    print(f"  Dashboard running at {url}")

    if open_browser:
        import webbrowser
        webbrowser.open(url)

    await stop_event.wait()
    await runner.cleanup()
