"""
Infrastructure management commands.

Provides:
    - evenage infra               # show current config
    - evenage infra list          # same as above
    - evenage infra add <name>    # enable backend (redis|postgres|minio)
    - evenage infra remove <name> # disable backend (-> memory|sqlite|local)
    - evenage infra switch key=val [key=val]  # switch backends
"""

from __future__ import annotations

import json
from pathlib import Path

import click

from evenage.cli.utils import console, print_error


def _project_root() -> Path | None:
    from evenage.cli.utils.config import find_project_root
    return find_project_root()


def _config_path(root: Path | None = None) -> Path:
    root = root or (_project_root() or Path.cwd())
    return root / ".evenage" / "config.json"


def _read_config(root: Path | None = None) -> dict:
    path = _config_path(root)
    try:
        if path.exists():
            return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        pass
    return {}


def _write_config(data: dict, root: Path | None = None) -> Path:
    root = root or (_project_root() or Path.cwd())
    path = root / ".evenage"
    path.mkdir(parents=True, exist_ok=True)
    cfg_path = path / "config.json"
    cfg_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
    return cfg_path


@click.group(name="infra", invoke_without_command=True)
@click.option(
    "--show-config/--no-show-config",
    default=True,
    help="Show configuration values",
)
@click.pass_context
def infra(ctx: click.Context, show_config: bool):
    """Manage infrastructure backends and view status."""
    if ctx.invoked_subcommand is not None:
        return
    try:
        from evenage.core.config import load_runtime_config
        config = load_runtime_config()

        console.print("\n[cyan bold]EvenAge Infrastructure[/cyan bold]\n")

        enable_scaling = config.queue_backend != "memory" or config.db_backend != "sqlite" or getattr(config, "storage_backend", "minio") != "local"
        console.print(f"[green]Enable scaling:[/green] {enable_scaling}")

        # Queue backend
        console.print(f"[green]Queue Backend:[/green] {config.queue_backend}")
        if config.queue_backend == "redis":
            console.print(f"  └─ URL: [dim]{config.redis_url}[/dim]")

        # Database backend
        console.print(f"\n[green]Database:[/green] {config.db_backend}")
        if show_config:
            console.print(f"  └─ URL: [dim]{config.database_url}[/dim]")

        # Storage backend
        storage_backend = getattr(config, "storage_backend", "minio")
        console.print(f"\n[green]Storage:[/green] {storage_backend}")
        if storage_backend == "minio" and show_config:
            console.print(f"  ├─ Endpoint: [dim]{config.minio_endpoint}[/dim]")
            console.print(f"  ├─ Bucket: [dim]{config.minio_bucket}[/dim]")
            console.print(f"  └─ Large response offload: [dim]{'enabled' if config.enable_large_response_storage else 'disabled'}[/dim]")
            if config.enable_large_response_storage:
                console.print(f"     └─ Threshold: [dim]{config.storage_threshold_kb} KB[/dim]")

        # Vector backend
        console.print(f"\n[green]Vector Store:[/green] {config.vector_backend}")
        if config.vector_backend == "pgvector" and show_config:
            console.print(f"  └─ Database: [dim]{config.database_url.split('@')[-1] if '@' in config.database_url else 'N/A'}[/dim]")

        # LLM backend
        console.print(f"\n[green]LLM Backend:[/green] {config.llm_backend}")
        if config.llm_model:
            console.print(f"  └─ Model: [dim]{config.llm_model}[/dim]")

        # Cache backend
        console.print(f"\n[green]Cache:[/green] {config.cache_backend}")
        if config.cache_backend == "redis" and show_config:
            console.print(f"  └─ URL: [dim]{config.redis_url}[/dim]")

        console.print()

    except Exception as e:
        print_error(f"Failed to show infrastructure: {e}")


@infra.command(name="list")
def list_backends():
    """List active backend selections from runtime config."""
    from evenage.core.config import load_runtime_config
    cfg = load_runtime_config()
    storage_backend = getattr(cfg, "storage_backend", "minio")
    console.print(
        json.dumps(
            {
                "queue_backend": cfg.queue_backend,
                "db_backend": cfg.db_backend,
                "storage_backend": storage_backend,
                "vector_backend": cfg.vector_backend,
                "llm_backend": cfg.llm_backend,
                "cache_backend": cfg.cache_backend,
            },
            indent=2,
        )
    )


@infra.command(name="add")
@click.argument("backend", type=click.Choice(["redis", "postgres", "minio"], case_sensitive=False))
def add_backend(backend: str):
    """Enable an integration backend and save to .evenage/config.json."""
    root = _project_root()
    if not root:
        print_error("Not inside an EvenAge project (evenage.yml not found)")
        return
    cfg = _read_config(root)
    cfg.setdefault("enable_scaling", True)
    if backend == "redis":
        cfg["queue_backend"] = "redis"
    elif backend == "postgres":
        cfg["db_backend"] = "postgres"
    elif backend == "minio":
        cfg["storage_backend"] = "minio"
    path = _write_config(cfg, root)
    console.print(f"[green]Updated[/green] {path}")
    console.print("Restart services to apply changes if running.")


@infra.command(name="remove")
@click.argument("backend", type=click.Choice(["redis", "postgres", "minio"], case_sensitive=False))
def remove_backend(backend: str):
    """Disable an integration backend (switch to local/memory/sqlite)."""
    root = _project_root()
    if not root:
        print_error("Not inside an EvenAge project (evenage.yml not found)")
        return
    cfg = _read_config(root)
    if backend == "redis":
        cfg["queue_backend"] = "inmemory" if "inmemory" in (cfg.get("queue_backend") or "") else "memory"
    elif backend == "postgres":
        cfg["db_backend"] = "sqlite"
    elif backend == "minio":
        cfg["storage_backend"] = "local"
    # enable_scaling auto-evaluates at runtime; keep as-is
    path = _write_config(cfg, root)
    console.print(f"[green]Updated[/green] {path}")
    console.print("Restart services to apply changes if running.")


@infra.command(name="switch")
@click.argument("pairs", nargs=-1)
def switch_backends(pairs: tuple[str, ...]):
    """Switch multiple backends at once. Example: evenage infra switch queue=redis db=postgres storage=minio"""
    root = _project_root()
    if not root:
        print_error("Not inside an EvenAge project (evenage.yml not found)")
        return
    cfg = _read_config(root)
    for p in pairs:
        if "=" not in p:
            continue
        k, v = p.split("=", 1)
        k = k.strip()
        v = v.strip()
        if k in {"queue", "queue_backend"}:
            cfg["queue_backend"] = v
        elif k in {"db", "db_backend", "database"}:
            cfg["db_backend"] = v
        elif k in {"storage", "storage_backend"}:
            cfg["storage_backend"] = v
        elif k in {"enable_scaling", "scaling"}:
            cfg["enable_scaling"] = (v.lower() in {"1", "true", "yes", "on"})
    path = _write_config(cfg, root)
    console.print(f"[green]Updated[/green] {path}")
    console.print("Restart services to apply changes if running.")
