#!/usr/bin/env python3
"""Launch the operator dashboard on localhost.

By default refuses any non-loopback --host because the dashboard ships
without authentication; pass --insecure-public to override (e.g. for
deliberate trusted-network exposure).
"""
from __future__ import annotations

import argparse
import sys
from pathlib import Path


LOOPBACK_HOSTS = frozenset({"127.0.0.1", "::1", "localhost"})


def is_loopback_host(host: str) -> bool:
    """Return True if `host` refers to a loopback interface."""
    return host.strip().lower() in LOOPBACK_HOSTS


def validate_host(host: str, insecure_public: bool) -> str | None:
    """Return an error message if the host/flag combination is unsafe, else None."""
    if is_loopback_host(host):
        return None
    if insecure_public:
        return None
    return (
        f"refusing to bind dashboard to non-loopback host {host!r}: "
        "the dashboard has no authentication. Re-run with --insecure-public "
        "to acknowledge the risk, or use --host 127.0.0.1 (default)."
    )


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument(
        "--personal",
        type=Path,
        default=None,
        help="Personal archive root (default: ~/.agent-learning or AGENT_LEARNING_PERSONAL).",
    )
    p.add_argument("--repo", type=Path, default=None, help="Optional repo root (back-compat).")
    p.add_argument(
        "--host",
        default="127.0.0.1",
        help=(
            "Bind address. Non-loopback values (anything other than 127.0.0.1, "
            "::1, or localhost) require --insecure-public."
        ),
    )
    p.add_argument("--port", type=int, default=8765)
    p.add_argument(
        "--insecure-public",
        action="store_true",
        help=(
            "Allow binding to a non-loopback --host. The dashboard has no auth; "
            "only use this on a trusted network."
        ),
    )
    return p.parse_args(argv)


def main():
    args = parse_args()
    err = validate_host(args.host, args.insecure_public)
    if err is not None:
        print(err, file=sys.stderr)
        return 2
    try:
        import uvicorn
    except ImportError:
        print(
            "uvicorn not installed; from the installed skill root run "
            "pip install -r requirements-optional.txt "
            "(archive root: pip install -r agent-learning-compounder/requirements-optional.txt)",
            file=sys.stderr,
        )
        return 2
    sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
    from dashboard import build_app
    app = build_app(
        personal=args.personal.resolve() if args.personal else None,
        repo=args.repo.resolve() if args.repo else None,
    )
    print(
        f"[serve_dashboard] dashboard on http://{args.host}:{args.port}/  "
        f"personal={args.personal or '(auto)'}",
        file=sys.stderr,
    )
    uvicorn.run(app, host=args.host, port=args.port, log_level="warning")


if __name__ == "__main__":
    sys.exit(main())
