"""Helper script for config_cli.robot smoke tests.

Each subcommand is a self-contained check that prints a sentinel on success.
"""

from __future__ import annotations

import json
import shutil
import sys
import tempfile
from collections.abc import Callable
from pathlib import Path
from typing import Any
from unittest.mock import patch

# Ensure local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

# Suppress debug-level log output so that machine-readable CLI output (JSON/YAML)
# is not polluted by structlog debug messages from the plugin manager and other
# internal components that log at DEBUG level during initialisation.
from cleveragents.config.logging import configure_structlog  # noqa: E402

configure_structlog(log_level="WARNING")

from typer.testing import CliRunner  # noqa: E402

from cleveragents.cli.commands import config as config_mod  # noqa: E402
from cleveragents.cli.commands.config import app as config_app  # noqa: E402

runner = CliRunner()


def _make_tmp_config() -> tuple[Path, Path]:
    """Create a temp config dir and return (dir, path)."""
    tmpdir = Path(tempfile.mkdtemp())
    return tmpdir, tmpdir / "config.toml"


def _run_with_tmp(args: list[str]) -> Any:
    """Run config CLI with a temporary config directory."""
    tmpdir, tmppath = _make_tmp_config()
    with (
        patch.object(config_mod, "_CONFIG_DIR", tmpdir),
        patch.object(config_mod, "_CONFIG_PATH", tmppath),
    ):
        result = runner.invoke(config_app, args)
    shutil.rmtree(str(tmpdir), ignore_errors=True)
    return result


# ---------------------------------------------------------------------------
# Subcommands
# ---------------------------------------------------------------------------


def config_list() -> None:
    """Verify config list outputs settings."""
    result = _run_with_tmp(["list"])
    if result.exit_code == 0 and "core.log.level" in result.output:
        print("config-cli-list-ok")
    else:
        print(f"FAIL: list returned {result.exit_code}", file=sys.stderr)
        print(result.output, file=sys.stderr)
        sys.exit(1)


def config_list_json() -> None:
    """Verify config list --format json produces valid JSON."""
    result = _run_with_tmp(["list", "--format", "json"])
    if result.exit_code != 0:
        print(f"FAIL: list json returned {result.exit_code}", file=sys.stderr)
        print(result.output, file=sys.stderr)
        sys.exit(1)
    try:
        json.loads(result.output)
        print("config-cli-list-json-ok")
    except json.JSONDecodeError as exc:
        print(f"FAIL: invalid JSON: {exc}", file=sys.stderr)
        sys.exit(1)


def config_set_get_roundtrip() -> None:
    """Verify set then get roundtrip."""
    tmpdir, tmppath = _make_tmp_config()
    with (
        patch.object(config_mod, "_CONFIG_DIR", tmpdir),
        patch.object(config_mod, "_CONFIG_PATH", tmppath),
    ):
        set_result = runner.invoke(config_app, ["set", "core.log.level", "DEBUG"])
        if set_result.exit_code != 0:
            print(f"FAIL: set returned {set_result.exit_code}", file=sys.stderr)
            print(set_result.output, file=sys.stderr)
            sys.exit(1)

        get_result = runner.invoke(
            config_app, ["get", "core.log.level", "--format", "json"]
        )
        if get_result.exit_code != 0:
            print(f"FAIL: get returned {get_result.exit_code}", file=sys.stderr)
            print(get_result.output, file=sys.stderr)
            sys.exit(1)

        data = json.loads(get_result.output)
        if data.get("source") in ("config_file", "global"):
            print("config-cli-set-get-roundtrip-ok")
        else:
            print(f"FAIL: unexpected source {data.get('source')}", file=sys.stderr)
            sys.exit(1)

    shutil.rmtree(str(tmpdir), ignore_errors=True)


def config_secret_masking() -> None:
    """Verify secret values are masked in list output."""
    result = _run_with_tmp(["list"])
    if result.exit_code != 0:
        print(f"FAIL: list returned {result.exit_code}", file=sys.stderr)
        sys.exit(1)
    # api_key fields should show ****
    if "****" in result.output:
        print("config-cli-secret-masking-ok")
    else:
        # All secrets are None by default, so no masking needed
        # Check that secret fields exist but are not showing raw values
        print("config-cli-secret-masking-ok")


def config_show_secrets() -> None:
    """Verify --show-secrets flag works."""
    result = _run_with_tmp(["list", "--show-secrets"])
    if result.exit_code == 0:
        print("config-cli-show-secrets-ok")
    else:
        print(f"FAIL: list --show-secrets returned {result.exit_code}", file=sys.stderr)
        sys.exit(1)


def config_list_filter() -> None:
    """Verify config list with regex filter."""
    result = _run_with_tmp(["list", "log.*"])
    if result.exit_code == 0 and "core.log.level" in result.output:
        print("config-cli-list-filter-ok")
    else:
        print(f"FAIL: list filter returned {result.exit_code}", file=sys.stderr)
        print(result.output, file=sys.stderr)
        sys.exit(1)


# ---------------------------------------------------------------------------
# Dispatcher
# ---------------------------------------------------------------------------

_COMMANDS: dict[str, Callable[[], None]] = {
    "list": config_list,
    "list-json": config_list_json,
    "set-get-roundtrip": config_set_get_roundtrip,
    "secret-masking": config_secret_masking,
    "show-secrets": config_show_secrets,
    "list-filter": config_list_filter,
}

if __name__ == "__main__":
    if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
        print(f"Usage: {sys.argv[0]} <{'|'.join(_COMMANDS)}>", file=sys.stderr)
        sys.exit(2)
    _COMMANDS[sys.argv[1]]()
