from __future__ import annotations

import json
import subprocess
import sys
import textwrap
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parents[1]


def run_cli(*args: str) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        [sys.executable, "-m", "cli.main", *args],
        cwd=PROJECT_ROOT,
        capture_output=True,
        text=True,
        check=False,
    )


def test_cli_exec_outputs_json(tmp_path) -> None:
    completed = run_cli(
        "--workspace",
        str(tmp_path),
        "exec",
        'util.echo(value="hello") -> msg',
    )

    payload = json.loads(completed.stdout)
    assert completed.returncode == 0
    assert payload["status"] == "success"
    assert payload["data"]["msg"] == "hello"
    assert payload["summary"]["policy"] == "standard"


def test_cli_run_executes_file(tmp_path) -> None:
    acl_file = tmp_path / "script.acl"
    acl_file.write_text('util.echo(value="file run") -> msg', encoding="utf-8")

    completed = run_cli("--workspace", str(tmp_path), "run", str(acl_file))

    payload = json.loads(completed.stdout)
    assert completed.returncode == 0
    assert payload["data"]["msg"] == "file run"


def test_cli_validate_and_dry_run_inline(tmp_path) -> None:
    validate_completed = run_cli(
        "--workspace",
        str(tmp_path),
        "validate",
        '--inline',
        'util.echo(value="hello") -> msg',
    )
    dry_run_completed = run_cli(
        "--workspace",
        str(tmp_path),
        "dry-run",
        '--inline',
        'util.echo(value="hello") -> msg',
    )

    validate_payload = json.loads(validate_completed.stdout)
    dry_run_payload = json.loads(dry_run_completed.stdout)
    assert validate_completed.returncode == 0
    assert validate_payload["data"]["commands"] == 1
    assert dry_run_completed.returncode == 0
    assert dry_run_payload["data"]["plan"][0]["action"] == "util.echo"


def test_cli_actions_lists_available_actions() -> None:
    completed = run_cli("actions")

    payload = json.loads(completed.stdout)
    assert completed.returncode == 0
    assert "util.echo" in payload["data"]["actions"]
    assert "file.exists" in payload["data"]["actions"]
    assert payload["data"]["policy"]["name"] == "standard"


def test_cli_supports_strict_policy(tmp_path) -> None:
    completed = run_cli(
        "--workspace",
        str(tmp_path),
        "--policy",
        "strict",
        "exec",
        'net.request(method="GET", url="https://example.com") -> response',
    )

    payload = json.loads(completed.stdout)
    assert completed.returncode == 1
    assert payload["error"]["code"] == "safety_error"
    assert payload["summary"]["policy"] == "strict"


def test_cli_continue_on_error_runs_remaining_steps(tmp_path) -> None:
    completed = run_cli(
        "--workspace",
        str(tmp_path),
        "--continue-on-error",
        "exec",
        'util.echo(value="first") -> first\nsystem.run(command="python", args=["-c", "print(1)"]) -> bad\nutil.echo(value="second") -> second',
    )

    payload = json.loads(completed.stdout)
    assert completed.returncode == 1
    assert payload["data"]["first"] == "first"
    assert payload["data"]["second"] == "second"
    assert len(payload["logs"]) == 3


def test_cli_can_load_plugin_actions(tmp_path) -> None:
    plugin = tmp_path / "plugin.py"
    plugin.write_text(
        textwrap.dedent(
            """\
            def shout(value: str):
                return value.upper()

            def register(registry):
                registry.register(
                    \"custom.shout\",
                    shout,
                    {\"value\": {\"type\": str, \"min_length\": 1}},
                    capabilities={\"utility\"},
                    description=\"Uppercase a value\",
                    returns=\"string\",
                )
            """
        ),
        encoding="utf-8",
    )

    completed = run_cli(
        "--plugin",
        str(plugin),
        "exec",
        'custom.shout(value="hello") -> result',
    )

    payload = json.loads(completed.stdout)
    assert completed.returncode == 0
    assert payload["data"]["result"] == "HELLO"


def test_cli_allow_capability_restricts_execution(tmp_path) -> None:
    completed = run_cli(
        "--workspace",
        str(tmp_path),
        "--allow-capability",
        "utility",
        "exec",
        'file.list(path=".") -> entries',
    )

    payload = json.loads(completed.stdout)
    assert completed.returncode == 1
    assert payload["error"]["code"] == "safety_error"
