# tests/test_idle_heartbeat_integration.py
import pytest
import asyncio
from pathlib import Path
from datetime import datetime, timedelta
from nanobot.agent.loop import AgentLoop
from nanobot.bus.queue import MessageBus
from nanobot.heartbeat.service import HeartbeatService
from nanobot.session.manager import SessionManager
from nanobot.providers.base import LLMProvider, LLMResponse
from unittest.mock import AsyncMock, MagicMock


@pytest.mark.asyncio
async def test_idle_heartbeat_end_to_end(tmp_path):
    """
    Integration test: heartbeat triggers when idle, runs in main session,
    output is suppressed, session contains [HIDDEN:signature] content.
    """
    workspace = tmp_path / "test-integration"
    workspace.mkdir()

    # Use test-specific session key
    test_session_key = "telegram:test_integration"

    # Create HEARTBEAT.md with content
    heartbeat_file = workspace / "HEARTBEAT.md"
    heartbeat_file.write_text("# Test Task\n- Check something")

    # Create mock provider
    provider = MagicMock(spec=LLMProvider)
    provider.chat = AsyncMock(return_value=LLMResponse(
        content="Heartbeat executed successfully",
        tool_calls=[]  # has_tool_calls is a property, not a parameter
    ))
    provider.get_default_model = MagicMock(return_value="test-model")
    provider.thinking_budget = 0

    # Create components
    bus = MessageBus()
    sessions = SessionManager(workspace)
    # Override sessions_dir to use tmp_path for test isolation
    sessions.sessions_dir = tmp_path / "sessions"
    sessions.sessions_dir.mkdir()
    loop = AgentLoop(
        bus=bus,
        provider=provider,
        workspace=workspace,
        session_manager=sessions
    )

    # Create session with old user message
    session = sessions.get_or_create(test_session_key)
    old_timestamp = (datetime.now() - timedelta(minutes=31)).isoformat()
    session.messages.append({
        "role": "user",
        "content": "Old user message",
        "timestamp": old_timestamp
    })
    sessions.save(session)

    # Create heartbeat callback
    async def on_heartbeat(prompt: str, metadata=None):
        return await loop.process_direct(
            prompt,
            session_key=test_session_key,
            channel="telegram",
            chat_id="test_integration",
            metadata=metadata,
        )

    # Create heartbeat service
    heartbeat = HeartbeatService(
        workspace=workspace,
        on_heartbeat=on_heartbeat,
        interval_s=1,
        enabled=True,
        session_manager=sessions,
        target_session_key=test_session_key,
        idle_threshold_s=30 * 60,
    )

    # Trigger heartbeat
    await heartbeat._tick()

    # Reload session from disk
    sessions._cache.clear()  # Clear cache to force reload
    session = sessions.get_or_create(test_session_key)

    # Verify:
    # 1. Session has new messages
    assert len(session.messages) > 1

    # 2. Find the heartbeat response (assistant message with signed visibility marker)
    heartbeat_messages = [
        m for m in session.messages
        if m.get("role") == "assistant" and "[HIDDEN:" in m.get("content", "")
    ]
    assert len(heartbeat_messages) == 1, "Expected exactly 1 [HIDDEN:signature] heartbeat message"

    # 3. Verify content is prefixed with [HIDDEN:signature]
    heartbeat_msg = heartbeat_messages[0]
    assert heartbeat_msg["content"].startswith("[HIDDEN:")
    # Verify signature format (8-char hex)
    content = heartbeat_msg["content"]
    prefix_end = content.index("]")
    signature = content[8:prefix_end]  # Skip "[HIDDEN:" to get signature
    assert len(signature) == 8, f"Expected 8-char signature, got {len(signature)}"
    assert all(c in "0123456789abcdef" for c in signature), "Signature should be hex"
    assert "Heartbeat executed successfully" in heartbeat_msg["content"]
