"""ACP CLI — local control plane via Docker Compose."""

from __future__ import annotations

import argparse
import shutil
import subprocess
import sys
import webbrowser

from acp.policies import init_policies, policies_dir, policies_status_lines
from acp.runtime import compose_env, compose_file, jwt_dir, runtime_dir

PROJECT_NAME = "acp"
GATEWAY_URL = "http://localhost:3090/dashboard/"
API_URL = "http://localhost:8080"


def _docker_compose_base() -> list[str]:
    if shutil.which("docker"):
        try:
            subprocess.run(
                ["docker", "compose", "version"],
                check=True,
                capture_output=True,
            )
            return ["docker", "compose"]
        except subprocess.CalledProcessError:
            pass
    if shutil.which("docker-compose"):
        return ["docker-compose"]
    raise RuntimeError("Docker Compose not found. Install Docker Desktop.")


def _compose_cmd(*args: str) -> list[str]:
    return [
        *_docker_compose_base(),
        "-f",
        str(compose_file()),
        "-p",
        PROJECT_NAME,
        *args,
    ]


def cmd_init(args: argparse.Namespace) -> int:
    dest = init_policies(force=args.force)
    print("ACP policy folder ready.")
    print(f"  {dest}")
    print("")
    for line in policies_status_lines():
        print(f"  {line}")
    print("")
    print("Edit .rego files here, then run:  acp up --build")
    print(f"Read: {dest / 'HOW_TO_ADD_RULES.md'}")
    return 0


def cmd_up(args: argparse.Namespace) -> int:
    runtime_dir()
    jd = jwt_dir()
    env = compose_env()
    pd = policies_dir()
    build = ["--build"] if args.build else []
    print(f"Starting ACP (project={PROJECT_NAME})…")
    print(f"  Runtime:  {runtime_dir()}")
    print(f"  Policies: {pd}")
    print(f"  JWT:      {jd}")
    rc = subprocess.call(_compose_cmd(*build, "up", "-d"), env=env)
    if rc != 0:
        return rc
    print("")
    print("ACP is running:")
    print(f"  Dashboard:  {GATEWAY_URL}")
    print(f"  API:        {API_URL}")
    print("")
    print("  export ACP_INTERCEPTOR_URL=http://localhost:8080")
    print(f"  Edit rules: {pd}")
    return 0


def cmd_down(_: argparse.Namespace) -> int:
    return subprocess.call(_compose_cmd("down"), env=compose_env())


def cmd_status(_: argparse.Namespace) -> int:
    rc = subprocess.call(_compose_cmd("ps"), env=compose_env())
    if rc != 0:
        return rc
    import urllib.request

    for label, url in [
        ("interceptor", f"{API_URL}/healthz"),
        ("gateway", "http://localhost:3090/healthz"),
    ]:
        try:
            with urllib.request.urlopen(url, timeout=3) as r:
                print(f"{label}: OK ({r.status})")
        except Exception as e:
            print(f"{label}: unreachable ({e})")
    for line in policies_status_lines():
        print(line)
    print(f"Dashboard: {GATEWAY_URL}")
    return 0


def cmd_dashboard(args: argparse.Namespace) -> int:
    url = args.url or GATEWAY_URL
    print(f"Opening {url}")
    webbrowser.open(url)
    return 0


def cmd_doctor(_: argparse.Namespace) -> int:
    ok = True
    print("✓ docker" if shutil.which("docker") else "✗ docker missing")
    ok = ok and bool(shutil.which("docker"))
    try:
        _docker_compose_base()
        print("✓ docker compose")
    except RuntimeError as e:
        print(f"✗ {e}")
        ok = False
    try:
        from importlib.resources import files as res_files

        b = res_files("acp").joinpath("bundle")
        print(f"✓ bundle in package: {b}")
    except Exception as e:
        print(f"✗ bundle: {e}")
        ok = False
    pd = policies_dir()
    if pd.is_dir() and any(pd.glob("*.rego")):
        print(f"✓ policies dir: {pd}")
    else:
        print(f"○ policies dir not initialized — run: acp init  ({pd})")
    return 0 if ok else 1


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        prog="acp",
        description="ACP (Agent Control Plane) — local governance stack",
    )
    sub = parser.add_subparsers(dest="command", required=True)

    init_p = sub.add_parser(
        "init",
        help="Create ~/.acp/policies with starter Rego (edit your rules here)",
    )
    init_p.add_argument(
        "--force",
        action="store_true",
        help="Overwrite existing starter .rego files",
    )
    init_p.set_defaults(func=cmd_init)

    up = sub.add_parser("up", help="Start OPA, Postgres, interceptor, dashboard")
    up.add_argument("--build", action="store_true", help="Rebuild interceptor image")
    up.set_defaults(func=cmd_up)

    sub.add_parser("down", help="Stop stack").set_defaults(func=cmd_down)
    sub.add_parser("status", help="Service status").set_defaults(func=cmd_status)

    dash = sub.add_parser("dashboard", help="Open dashboard in browser")
    dash.add_argument("--url", default=None)
    dash.set_defaults(func=cmd_dashboard)

    sub.add_parser("doctor", help="Check install prerequisites").set_defaults(func=cmd_doctor)

    args = parser.parse_args(argv)
    return int(args.func(args))


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