"""Tests for is_provider_explicitly_configured()."""

import json
import pytest


def _write_config(tmp_path, config: dict) -> None:
    hermes_home = tmp_path / "hermes"
    hermes_home.mkdir(parents=True, exist_ok=True)
    import hermes_yaml as yaml
    (hermes_home / "config.yaml").write_text(yaml.safe_dump(config))


def _write_auth_store(tmp_path, payload: dict) -> None:
    hermes_home = tmp_path / "hermes"
    hermes_home.mkdir(parents=True, exist_ok=True)
    (hermes_home / "auth.json").write_text(json.dumps(payload, indent=2))


@pytest.fixture(autouse=True)
def _clean_anthropic_env(monkeypatch):
    """Strip Anthropic env vars so CI secrets don't leak into tests."""
    for key in ("ANTHROPIC_API_KEY", "ANTHROPIC_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN"):
        monkeypatch.delenv(key, raising=False)






def test_ambient_pool_source_does_not_count_as_explicit(tmp_path, monkeypatch):
    """gh_cli-seeded Copilot pool entries are ambient, not explicit config (#56974)."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    monkeypatch.delenv("COPILOT_GITHUB_TOKEN", raising=False)
    monkeypatch.delenv("GH_TOKEN", raising=False)
    monkeypatch.delenv("GITHUB_TOKEN", raising=False)
    _write_auth_store(tmp_path, {
        "version": 1,
        "providers": {},
        "active_provider": None,
        "credential_pool": {
            "copilot": [{
                "id": "abc123",
                "source": "gh_cli",
                "auth_type": "api_key",
                "access_token": "ghu_sometoken",
            }],
        },
    })

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("copilot") is False


def test_vertex_adc_counts_as_explicit_when_config_present(tmp_path, monkeypatch):
    """A keyless Vertex provider is explicitly configured when the user pointed
    Hermes at it (VERTEX_PROJECT_ID / vertex.project_id / VERTEX_CREDENTIALS_PATH),
    even when it is NOT the current provider — otherwise it silently vanishes
    from explicit-only pickers (desktop chat model menu) unless already selected."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    for var in ("VERTEX_PROJECT_ID", "VERTEX_CREDENTIALS_PATH", "GOOGLE_APPLICATION_CREDENTIALS"):
        monkeypatch.delenv(var, raising=False)
    _write_auth_store(tmp_path, {"version": 1, "providers": {}, "active_provider": None})

    from hermes_cli.auth import is_provider_explicitly_configured

    # vertex.project_id in config.yaml is a deliberate, Hermes-scoped signal.
    _write_config(tmp_path, {
        "model": {"provider": "anthropic", "default": "claude-opus-4-8"},
        "vertex": {"project_id": "my-gcp-project"},
    })
    assert is_provider_explicitly_configured("vertex") is True

    # No Hermes-scoped Vertex config at all → stays hidden.
    _write_config(tmp_path, {"model": {"provider": "anthropic", "default": "claude-opus-4-8"}})
    assert is_provider_explicitly_configured("vertex") is False


def test_vertex_ambient_google_creds_env_does_not_count_as_explicit(tmp_path, monkeypatch):
    """An ambient GOOGLE_APPLICATION_CREDENTIALS path (commonly set globally for
    unrelated GCP work) must NOT mark Vertex explicit — only Hermes-scoped
    signals do. Regression guard for the picker gate (PR review feedback)."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    monkeypatch.delenv("VERTEX_PROJECT_ID", raising=False)
    monkeypatch.delenv("VERTEX_CREDENTIALS_PATH", raising=False)
    _write_config(tmp_path, {"model": {"provider": "anthropic", "default": "claude-opus-4-8"}})
    _write_auth_store(tmp_path, {"version": 1, "providers": {}, "active_provider": None})

    # A real, existing SA file pointed to ONLY by the ambient Google var.
    sa = tmp_path / "adc.json"
    sa.write_text("{}")
    monkeypatch.setenv("GOOGLE_APPLICATION_CREDENTIALS", str(sa))

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("vertex") is False


def test_vertex_credentials_path_must_be_readable_file(tmp_path, monkeypatch):
    """VERTEX_CREDENTIALS_PATH must point to an actual readable file, not a directory
    or non-existent path."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    monkeypatch.delenv("VERTEX_PROJECT_ID", raising=False)
    monkeypatch.delenv("GOOGLE_APPLICATION_CREDENTIALS", raising=False)
    _write_config(tmp_path, {"model": {"provider": "anthropic", "default": "claude-opus-4-8"}})
    _write_auth_store(tmp_path, {"version": 1, "providers": {}, "active_provider": None})

    from hermes_cli.auth import is_provider_explicitly_configured

    # Valid readable file -> True
    sa_file = tmp_path / "vertex_sa.json"
    sa_file.write_text("{}")
    monkeypatch.setenv("VERTEX_CREDENTIALS_PATH", str(sa_file))
    assert is_provider_explicitly_configured("vertex") is True

    # Directory -> False
    sa_dir = tmp_path / "vertex_dir"
    sa_dir.mkdir()
    monkeypatch.setenv("VERTEX_CREDENTIALS_PATH", str(sa_dir))
    assert is_provider_explicitly_configured("vertex") is False

    # Non-existent file -> False
    monkeypatch.setenv("VERTEX_CREDENTIALS_PATH", str(tmp_path / "nonexistent.json"))
    assert is_provider_explicitly_configured("vertex") is False


def test_bedrock_region_counts_as_explicit(tmp_path, monkeypatch):
    """Bedrock (AWS SDK auth, no API key) is explicitly configured once the
    user pins a region in config.yaml, mirroring the Vertex keyless case."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    _write_auth_store(tmp_path, {"version": 1, "providers": {}, "active_provider": None})

    from hermes_cli.auth import is_provider_explicitly_configured

    _write_config(tmp_path, {
        "model": {"provider": "anthropic", "default": "claude-opus-4-8"},
        "bedrock": {"region": "us-east-1"},
    })
    assert is_provider_explicitly_configured("bedrock") is True

    _write_config(tmp_path, {
        "model": {"provider": "anthropic", "default": "claude-opus-4-8"},
        "bedrock": {"region": ""},
    })
    assert is_provider_explicitly_configured("bedrock") is False


def test_returns_true_when_moa_reference_slot_uses_provider(tmp_path, monkeypatch):
    """MoA advisor slots are explicit provider selections for auth gating."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    _write_config(tmp_path, {
        "model": {"provider": "openai-codex", "default": "gpt-5.5"},
        "moa": {
            "presets": {
                "default": {
                    "reference_models": [
                        {"provider": "anthropic", "model": "claude-opus-4-8"},
                        {"provider": "opencode-go", "model": "glm-5.2"},
                    ],
                    "aggregator": {"provider": "openai-codex", "model": "gpt-5.5"},
                }
            }
        },
    })
    _write_auth_store(tmp_path, {"version": 1, "providers": {}, "active_provider": "openai-codex"})

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("anthropic") is True


def test_stale_env_pool_entry_does_not_count_when_var_unset(tmp_path, monkeypatch):
    """An env-seeded pool entry left in auth.json after the env var was removed
    must not mark the provider configured (#55790): the picker showed removed
    providers forever because the record existed even though no secret resolves."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False)
    _write_auth_store(tmp_path, {
        "version": 1,
        "providers": {},
        "active_provider": None,
        "credential_pool": {
            "deepseek": [{
                "id": "aaa111",
                "source": "env:DEEPSEEK_API_KEY",
                "auth_type": "api_key",
            }],
        },
    })

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("deepseek") is False


def test_profile_dotenv_key_counts_as_explicit_when_process_env_lacks_it(tmp_path, monkeypatch):
    """A DeepSeek key in a named profile's .env must count under that profile's
    secret scope even when os.environ (the launch profile) has no DeepSeek var.

    Desktop Settings → Model uses explicit_only, which filters through
    is_provider_explicitly_configured. os.getenv hid the keyed provider until
    Refresh models ran against the bot's own backend.
    """
    root = tmp_path / "hermes"
    studio = root / "profiles" / "content-studio"
    studio.mkdir(parents=True)
    (root / "config.yaml").write_text("model: {}\n")
    (studio / "config.yaml").write_text("model: {}\n")
    (studio / ".env").write_text("DEEPSEEK_API_KEY=sk-studio-deepseek-key\n")
    monkeypatch.setenv("HERMES_HOME", str(root))
    monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False)

    from agent import secret_scope
    from tui_gateway import launch_profile_policy as lpp
    monkeypatch.setattr(secret_scope, "_MULTIPLEX_ACTIVE", False)
    monkeypatch.setattr(lpp, "_snapshot", None)

    from hermes_cli.auth import is_provider_explicitly_configured
    from hermes_cli.web_server_profiles import _config_profile_scope

    assert is_provider_explicitly_configured("deepseek") is False
    with _config_profile_scope("content-studio"):
        assert is_provider_explicitly_configured("deepseek") is True
    with _config_profile_scope(None):
        assert is_provider_explicitly_configured("deepseek") is False


def test_dotenv_key_counts_when_shell_exports_the_var_empty(tmp_path, monkeypatch):
    """The gate resolves through the same reader as the credential resolver
    (get_env_value_prefer_dotenv), so it agrees with the key that authenticates:
    an empty ``DEEPSEEK_API_KEY=`` inherited from the parent shell must not hide
    a real key in .env (#77007) — the resolver would use that key, so the picker
    must list the provider."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    monkeypatch.setenv("DEEPSEEK_API_KEY", "")
    _write_config(tmp_path, {"model": {}})
    (tmp_path / "hermes" / ".env").write_text("DEEPSEEK_API_KEY=sk-dotenv-only-secret\n")

    from hermes_cli.auth import is_provider_explicitly_configured, resolve_api_key_provider_credentials
    assert resolve_api_key_provider_credentials("deepseek").get("api_key") == "sk-dotenv-only-secret"
    assert is_provider_explicitly_configured("deepseek") is True


# ─── aws_sdk providers (Bedrock) ─────────────────────────────────────────
#
# Bedrock is registered with auth_type="aws_sdk" and an empty
# api_key_env_vars tuple, so the api_key env-var loop never sees it.
# Setting AWS_BEARER_TOKEN_BEDROCK (or an access-key pair) in .env is
# exactly as explicit as pasting ANTHROPIC_API_KEY, and must count —
# otherwise the desktop picker's explicit_only filter hides Bedrock even
# though list_authenticated_providers builds a full row for it.
#
# Ambient AWS credential sources (SSO profiles, EC2 IMDS, container
# credentials) must NOT count: aws_sdk detection here is env-var only,
# never boto3's full chain.


@pytest.fixture()
def _clean_aws_env(monkeypatch):
    """Strip AWS env vars so developer/CI AWS credentials don't leak in."""
    for key in (
        "AWS_BEARER_TOKEN_BEDROCK",
        "AWS_ACCESS_KEY_ID",
        "AWS_SECRET_ACCESS_KEY",
        "AWS_SESSION_TOKEN",
        "AWS_PROFILE",
        "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
        "AWS_WEB_IDENTITY_TOKEN_FILE",
    ):
        monkeypatch.delenv(key, raising=False)


def test_bedrock_not_explicit_without_aws_env(tmp_path, monkeypatch, _clean_aws_env):
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("bedrock") is False


def test_bedrock_bearer_token_counts_as_explicit(tmp_path, monkeypatch, _clean_aws_env):
    """AWS_BEARER_TOKEN_BEDROCK is Bedrock-specific — the user set it for
    exactly this provider, so it gates like a provider API key."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "ABSKexample-bearer-token-value")

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("bedrock") is True


def test_bedrock_access_key_pair_counts_as_explicit(tmp_path, monkeypatch, _clean_aws_env):
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("AWS_ACCESS_KEY_ID", "AKIAEXAMPLE1234567890")
    monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "examplesecretexamplesecretexample0000000")

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("bedrock") is True


def test_bedrock_access_key_without_secret_is_not_explicit(tmp_path, monkeypatch, _clean_aws_env):
    """A lone AWS_ACCESS_KEY_ID can't authenticate anything — require the pair."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("AWS_ACCESS_KEY_ID", "AKIAEXAMPLE1234567890")

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("bedrock") is False


def test_bedrock_ambient_aws_profile_is_not_explicit(tmp_path, monkeypatch, _clean_aws_env):
    """AWS_PROFILE is ambient machine state (SSO / shared credentials file),
    not an explicit Hermes provider choice — same principle as gh_cli-seeded
    Copilot pool entries (#56974)."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("AWS_PROFILE", "default")

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("bedrock") is False


def test_aws_env_does_not_leak_into_other_providers(tmp_path, monkeypatch, _clean_aws_env):
    """The aws_sdk env check must key on the provider's auth_type, not fire
    for every provider whenever AWS credentials happen to be present."""
    monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
    (tmp_path / "hermes").mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "ABSKexample-bearer-token-value")

    from hermes_cli.auth import is_provider_explicitly_configured
    assert is_provider_explicitly_configured("anthropic") is False
