"""Regression coverage for fail-closed non-interactive config startup."""

from __future__ import annotations

import logging
import os
import sys
import types
from argparse import Namespace

import pytest

def _args(**overrides) -> Namespace:
    values = {
        "command": "chat",
        "ignore_user_config": False,
        "oneshot": None,
        "query": "hello",
        "quiet": False,
        "safe_mode": False,
        "yolo": False,
    }
    values.update(overrides)
    return Namespace(**values)

@pytest.fixture(autouse=True)
def _isolated_config_env(monkeypatch, tmp_path):
    monkeypatch.setenv("HERMES_HOME", str(tmp_path))
    monkeypatch.delenv("HERMES_IGNORE_USER_CONFIG", raising=False)
    yield
    os.environ.pop("HERMES_IGNORE_USER_CONFIG", None)

@pytest.mark.parametrize(
    "args",
    [
        _args(query="hello"),
        _args(command=None, query=None, oneshot="hello"),
        _args(query="hello", quiet=True),
    ],
    ids=["single-query", "oneshot", "quiet-query"],
)
def test_noninteractive_guard_rejects_malformed_yaml(args, tmp_path, caplog, capsys):
    from hermes_cli import main as main_mod

    broken = "model: [unterminated\n"
    config_path = tmp_path / "config.yaml"
    config_path.write_text(broken, encoding="utf-8")

    with caplog.at_level(logging.ERROR, logger="hermes_cli.config"):
        with pytest.raises(SystemExit) as exc_info:
            main_mod._guard_noninteractive_user_config(args)

    assert exc_info.value.code == 2
    assert capsys.readouterr().err.strip()
    assert any(record.levelno == logging.ERROR for record in caplog.records)
    assert config_path.read_text(encoding="utf-8") == broken
    backups = list((tmp_path / "backups" / "config").glob("config.yaml.corrupt.*"))
    assert len(backups) == 1
    assert backups[0].read_text(encoding="utf-8") == broken

def test_prepare_rejects_bad_config_before_plugin_discovery(monkeypatch, tmp_path):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("model: [unterminated\n")
    discovery_calls = []
    monkeypatch.setitem(
        sys.modules,
        "hermes_cli.plugins",
        types.SimpleNamespace(
            discover_plugins=lambda: discovery_calls.append("plugins")
        ),
    )

    with pytest.raises(SystemExit) as exc_info:
        main_mod._prepare_agent_startup(_args())

    assert exc_info.value.code == 2
    assert discovery_calls == []

@pytest.mark.parametrize(
    "content", [None, "", "{}\n", "model:\n  default: local/test\n"]
)
def test_noninteractive_guard_accepts_missing_empty_and_mapping_configs(
    content, tmp_path
):
    from hermes_cli import main as main_mod

    if content is not None:
        (tmp_path / "config.yaml").write_text(content, encoding="utf-8")
    args = _args()

    main_mod._guard_noninteractive_user_config(args)

    assert args._noninteractive_config_validated is True

def test_noninteractive_guard_rejects_non_mapping_yaml(tmp_path, capsys):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("- model\n- provider\n")

    with pytest.raises(SystemExit) as exc_info:
        main_mod._guard_noninteractive_user_config(_args())

    assert exc_info.value.code == 2
    assert capsys.readouterr().err.strip()

@pytest.mark.parametrize(
    "args",
    [
        _args(ignore_user_config=True),
        _args(safe_mode=True),
    ],
    ids=["ignore-user-config", "safe-mode"],
)
def test_explicit_config_bypasses_allow_noninteractive_recovery(args, tmp_path):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("model: [unterminated\n")

    main_mod._guard_noninteractive_user_config(args)

    assert args._noninteractive_config_validated is True
    assert list(tmp_path.rglob("config.yaml.corrupt.*")) == []

def test_interactive_chat_keeps_existing_repair_behavior(tmp_path):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("model: [unterminated\n")
    args = _args(query=None)

    main_mod._guard_noninteractive_user_config(args)

    assert not hasattr(args, "_noninteractive_config_validated")
    assert list(tmp_path.rglob("config.yaml.corrupt.*")) == []

@pytest.mark.parametrize(
    "args",
    [
        _args(query=""),
        _args(query=None, quiet=True),
        _args(query="", quiet=True),
    ],
    ids=["empty-query", "quiet", "quiet-empty-query"],
)
def test_queryless_chat_keeps_interactive_repair_behavior(args, tmp_path):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("model: [unterminated\n")

    main_mod._guard_noninteractive_user_config(args)

    assert not hasattr(args, "_noninteractive_config_validated")
    assert list(tmp_path.rglob("config.yaml.corrupt.*")) == []

def test_env_only_config_bypass_allows_noninteractive_recovery(monkeypatch, tmp_path):
    from hermes_cli import main as main_mod

    (tmp_path / "config.yaml").write_text("model: [unterminated\n")
    monkeypatch.setenv("HERMES_IGNORE_USER_CONFIG", "1")
    args = _args()

    main_mod._guard_noninteractive_user_config(args)

    assert args._noninteractive_config_validated is True
    assert list(tmp_path.rglob("config.yaml.corrupt.*")) == []

def test_reused_args_can_retry_after_config_repair(tmp_path):
    from hermes_cli import main as main_mod

    config_path = tmp_path / "config.yaml"
    config_path.write_text("model: [unterminated\n")
    args = _args()

    with pytest.raises(SystemExit):
        main_mod._guard_noninteractive_user_config(args)

    config_path.write_text("model:\n  default: local/test\n")
    main_mod._guard_noninteractive_user_config(args)

    assert args._noninteractive_config_validated is True
