"""Tests for the managed Hermes response-transform lifecycle patch."""

from __future__ import annotations

import importlib.util
from pathlib import Path

import pytest

ROOT = Path(__file__).resolve().parents[1]
PATCHER = ROOT / "hermes-agent" / "patches" / "apply_response_transform_hook.py"


def load_patcher():
    spec = importlib.util.spec_from_file_location("hermes_response_transform_patcher", PATCHER)
    assert spec and spec.loader
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


def upstream_fixture() -> str:
    return '''class Agent:
    def run(self, messages, user_message, completed, effective_task_id, conversation_history,
            final_response, interrupted, original_user_message):
        # Save trajectory if enabled
        self._save_trajectory(messages, user_message, completed)

        # Clean up VM and browser for this task after conversation completes
        self._cleanup_task_resources(effective_task_id)

        # Persist session to both JSON log and SQLite
        self._persist_session(messages, conversation_history)


        # Plugin hook: post_llm_call
        if final_response and not interrupted:
            from hermes_cli.plugins import invoke_hook as _invoke_hook
            _invoke_hook(
                "post_llm_call",
                session_id=self.session_id,
                user_message=original_user_message,
                assistant_response=final_response,
            )

        # Extract reasoning from the last assistant message (if any)
        last_reasoning = None
        return final_response, last_reasoning
'''


def test_patch_moves_response_transform_before_persistence_and_is_idempotent() -> None:
    module = load_patcher()
    patched, changed = module.patch_source(upstream_fixture())

    assert changed is True
    assert module.PATCH_MARKER in patched
    assert patched.index('_candidate = _post_result.get("assistant_response")') < patched.index(
        "self._save_trajectory(messages, user_message, completed)"
    )
    assert patched.index("self._save_trajectory(messages, user_message, completed)") < patched.index(
        "self._persist_session(messages, conversation_history)"
    )
    assert module.patch_source(patched) == (patched, False)


def test_patch_refuses_unknown_hermes_lifecycle() -> None:
    module = load_patcher()
    with pytest.raises(ValueError, match="anchors changed"):
        module.patch_source("class Agent:\n    pass\n")


def test_install_check_reports_patch_required_then_installed(tmp_path: Path) -> None:
    module = load_patcher()
    target = tmp_path / "run_agent.py"
    target.write_text(upstream_fixture(), encoding="utf-8")

    before, before_code = module.install(target, check=True)
    assert before_code == 1
    assert before["status"] == "patch_required"

    applied, applied_code = module.install(target, check=False)
    assert applied_code == 0
    assert applied["status"] == "installed_now"

    after, after_code = module.install(target, check=True)
    assert after_code == 0
    assert after["status"] == "installed"


def test_runtime_installer_manages_response_and_telegram_name_patches(tmp_path: Path) -> None:
    module = load_patcher()
    run_agent = tmp_path / "run_agent.py"
    telegram = tmp_path / "gateway" / "platforms" / "telegram.py"
    telegram.parent.mkdir(parents=True)
    run_agent.write_text(upstream_fixture(), encoding="utf-8")
    telegram.write_text(
        '''def build_source(user):
    return dict(
            user_id=str(user.id) if user else None,
            user_name=user.full_name if user else None,
    )
''',
        encoding="utf-8",
    )

    before, before_code = module.install_runtime(run_agent, check=True)
    assert before_code == 1
    assert before["status"] == "patch_required"

    applied, applied_code = module.install_runtime(run_agent, check=False)
    assert applied_code == 0
    assert applied["status"] == "installed_now"
    assert applied["response_transform"]["status"] == "installed_now"
    assert applied["telegram_sender_name_policy"]["status"] == "installed_now"

    after, after_code = module.install_runtime(run_agent, check=True)
    assert after_code == 0
    assert after["status"] == "installed"
