"""Regression tests for the delegation.request_overrides config key.

PR #90953 (salvage): ``delegation.request_overrides`` is an explicit dict of
per-child request settings that must be honored on EVERY resolution branch of
``_resolve_delegation_credentials``:

1. direct base_url (provider=custom) — the branch the original PR fixed,
2. named provider (delegation.provider set, no base_url),
3. parent-inherit (neither provider nor base_url).

Precedence contract (post-#98237): explicit config values merge OVER
runtime/parent-derived overrides — top-level explicit keys win; the
``extra_body`` sub-dict is deep-merged one level so runtime extra_body keys
survive unless the explicit key redefines them. Nested values are deep-copied
so transport-side mutation cannot leak back into config.
"""

from unittest.mock import MagicMock, patch

from tools.delegate_tool import (
    _merge_request_overrides,
    _resolve_delegation_credentials,
)


def _cfg(**overrides):
    cfg = {
        "model": "deepseek/deepseek-v4-flash-0731",
        "base_url": "https://openrouter.ai/api/v1",
        "api_key": "test-key-1234567890",
    }
    cfg.update(overrides)
    return cfg


def _parent(**attrs):
    parent = MagicMock()
    parent._delegate_depth = 0
    # MagicMock attributes are MagicMocks (non-dict) by default; set real
    # values for the ones the resolution path inspects.
    parent.request_overrides = attrs.pop("request_overrides", None)
    for k, v in attrs.items():
        setattr(parent, k, v)
    return parent


# ── Branch 1: direct base_url ──────────────────────────────────────────────


def test_direct_branch_forwards_request_overrides():
    """delegation.request_overrides flows through the direct-endpoint branch."""
    cfg = _cfg(
        request_overrides={
            "extra_body": {"provider": {"sort": "throughput"}},
        }
    )
    creds = _resolve_delegation_credentials(cfg, parent_agent=None)
    assert creds["request_overrides"] == {
        "extra_body": {"provider": {"sort": "throughput"}},
    }
    # Dedicated user cap controls are not part of child credentials.
    assert "max_output_tokens" not in creds


def test_direct_branch_absent_request_overrides_stays_none():
    """No delegation.request_overrides → None, preserving the old contract."""
    creds = _resolve_delegation_credentials(_cfg(), parent_agent=None)
    assert creds["request_overrides"] is None


def test_direct_branch_non_dict_request_overrides_stays_none():
    """Garbage in config (string/list) must not crash or forward junk."""
    for bad in ("throughput", ["extra_body"], 42):
        creds = _resolve_delegation_credentials(
            _cfg(request_overrides=bad), parent_agent=None
        )
        assert creds["request_overrides"] is None


def test_direct_branch_deep_copies_nested_extra_body():
    """Transport-side mutation of the child's overrides must not leak back
    into the config dict (copy.deepcopy, not a shallow dict())."""
    source = {"extra_body": {"provider": {"sort": "throughput"}}}
    cfg = _cfg(request_overrides=source)
    creds = _resolve_delegation_credentials(cfg, parent_agent=None)
    creds["request_overrides"]["extra_body"]["provider"]["sort"] = "mutated"
    creds["request_overrides"]["extra_body"]["injected"] = True
    assert source == {"extra_body": {"provider": {"sort": "throughput"}}}


@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_explicit_merges_over_runtime_on_provider_alongside_base_url(mock_resolve):
    """Precedence on the provider-alongside-base_url path (#98237 interplay):
    explicit delegation.request_overrides merges OVER the named provider's
    runtime overrides — runtime extra_body keys survive unless redefined,
    explicit top-level keys win, and legacy max_output_tokens is ignored."""
    mock_resolve.return_value = {
        "provider": "custom",
        "base_url": "https://provider-default.example/v1",
        "api_key": "provider-key",
        "api_mode": "chat_completions",
        "request_overrides": {
            "service_tier": "default",
            "extra_body": {"thinking": {"type": "disabled"}, "provider": {"sort": "price"}},
        },
        "max_output_tokens": 8192,
    }
    cfg = _cfg(
        provider="mimo",
        request_overrides={
            "service_tier": "flex",
            "extra_body": {"provider": {"sort": "throughput"}},
        },
    )
    creds = _resolve_delegation_credentials(cfg, parent_agent=None)
    assert creds["request_overrides"] == {
        # explicit top-level key wins
        "service_tier": "flex",
        "extra_body": {
            # runtime extra_body key survives (not redefined)
            "thinking": {"type": "disabled"},
            # explicit extra_body key wins over runtime's
            "provider": {"sort": "throughput"},
        },
    }
    assert "max_output_tokens" not in creds


# ── Branch 2: named provider (no base_url) ─────────────────────────────────


@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_named_provider_branch_honors_explicit_key(mock_resolve):
    """The named-provider branch merges the explicit key over the provider's
    runtime overrides — the config key never silently no-ops."""
    mock_resolve.return_value = {
        "provider": "openrouter",
        "base_url": "https://openrouter.ai/api/v1",
        "api_key": "runtime-key",
        "api_mode": "chat_completions",
        "request_overrides": {"extra_body": {"reasoning": {"enabled": True}}},
        "max_output_tokens": 4096,
    }
    cfg = {
        "model": "deepseek/deepseek-v4-flash-0731",
        "provider": "openrouter",
        "request_overrides": {"extra_body": {"provider": {"sort": "throughput"}}},
    }
    creds = _resolve_delegation_credentials(cfg, parent_agent=None)
    assert creds["request_overrides"] == {
        "extra_body": {
            "reasoning": {"enabled": True},
            "provider": {"sort": "throughput"},
        }
    }


@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_named_provider_branch_without_explicit_key_unchanged(mock_resolve):
    """Without the config key the named-provider branch behaves as before."""
    mock_resolve.return_value = {
        "provider": "openrouter",
        "base_url": "https://openrouter.ai/api/v1",
        "api_key": "runtime-key",
        "api_mode": "chat_completions",
        "request_overrides": {"extra_body": {"reasoning": {"enabled": True}}},
        "max_output_tokens": 4096,
    }
    cfg = {"model": "m", "provider": "openrouter"}
    creds = _resolve_delegation_credentials(cfg, parent_agent=None)
    assert creds["request_overrides"] == {"extra_body": {"reasoning": {"enabled": True}}}


# ── Branch 3: parent-inherit (no provider, no base_url) ────────────────────


def test_inherit_branch_honors_explicit_key_over_parent():
    """Pure-inherit setups still apply delegation.request_overrides, merged
    over the parent agent's own request_overrides."""
    parent = _parent(
        request_overrides={
            "service_tier": "default",
            "extra_body": {"thinking": {"type": "disabled"}},
        }
    )
    cfg = {
        "model": "",
        "provider": "",
        "request_overrides": {"extra_body": {"provider": {"sort": "throughput"}}},
    }
    creds = _resolve_delegation_credentials(cfg, parent)
    assert creds["request_overrides"] == {
        "service_tier": "default",
        "extra_body": {
            "thinking": {"type": "disabled"},
            "provider": {"sort": "throughput"},
        },
    }


def test_inherit_branch_without_key_stays_none():
    """No explicit key and no parent overrides → None (old contract: the
    child's construction path falls back to the parent's request_overrides)."""
    parent = _parent(request_overrides=None)
    creds = _resolve_delegation_credentials({"model": "", "provider": ""}, parent)
    assert creds["request_overrides"] is None


def test_inherit_branch_deep_copies_parent_overrides():
    """Parent's nested overrides must be deep-copied on the inherit branch."""
    parent_overrides = {"extra_body": {"thinking": {"type": "disabled"}}}
    parent = _parent(request_overrides=parent_overrides)
    cfg = {
        "model": "",
        "provider": "",
        "request_overrides": {"extra_body": {"provider": {"sort": "throughput"}}},
    }
    creds = _resolve_delegation_credentials(cfg, parent)
    creds["request_overrides"]["extra_body"]["thinking"]["type"] = "mutated"
    assert parent_overrides == {"extra_body": {"thinking": {"type": "disabled"}}}


# ── Merge helper unit tests ────────────────────────────────────────────────


def test_merge_helper_both_none():
    assert _merge_request_overrides(None, None) is None
    assert _merge_request_overrides({}, {}) is None
    assert _merge_request_overrides("junk", 42) is None










def test_merge_helper_non_dict_runtime_extra_body_replaced():
    merged = _merge_request_overrides(
        {"extra_body": "junk"}, {"extra_body": {"a": 1}}
    )
    assert merged == {"extra_body": {"a": 1}}
