# tests/test_heartbeat_idle_detection.py
"""Tests for heartbeat idle detection with sender_id filtering."""
import pytest
from datetime import datetime, timedelta
from pathlib import Path
from nanobot.heartbeat.service import HeartbeatService
from nanobot.session.manager import Session, SessionManager


@pytest.mark.asyncio
async def test_idle_detection_ignores_system_messages():
    """Test that heartbeat only counts real user messages for idle detection."""
    # Create session manager and session
    session_manager = SessionManager(workspace=Path("/tmp/test-heartbeat"))
    session = session_manager.get_or_create("telegram:239824268")

    # Add a real user message 45 minutes ago
    real_user_time = datetime.now() - timedelta(minutes=45)
    session.add_message(
        "user",
        "This is a real user message",
        sender_id="239824268|testuser",
        timestamp=real_user_time.isoformat()
    )

    # Add a heartbeat system message 10 minutes ago (should be ignored)
    heartbeat_time = datetime.now() - timedelta(minutes=10)
    session.add_message(
        "user",
        "Read HEARTBEAT.md...",
        sender_id="user",
        timestamp=heartbeat_time.isoformat()
    )

    # Add an assistant response
    session.add_message("assistant", "Response to heartbeat")

    # Create heartbeat service with 30 minute idle threshold
    heartbeat = HeartbeatService(
        workspace=Path("/tmp/test-heartbeat"),
        session_manager=session_manager,
        target_session_key="telegram:239824268",
        idle_threshold_s=30 * 60,  # 30 minutes
        interval_s=30 * 60,
        enabled=False  # Don't actually start the loop
    )

    # Manually check idle logic (replicate _tick logic)
    session = session_manager.get_or_create("telegram:239824268")

    # Find last user message timestamp (should find the 45-minute-old message, not the 10-minute-old one)
    last_user_timestamp = None
    for msg in reversed(session.messages):
        if msg.get("role") == "user":
            sender_id = msg.get("sender_id")
            if sender_id == "user":
                continue
            last_user_timestamp = msg.get("timestamp")
            break

    assert last_user_timestamp is not None
    last_dt = datetime.fromisoformat(last_user_timestamp)
    elapsed = (datetime.now() - last_dt).total_seconds()

    # Should detect user is idle (45 minutes > 30 minute threshold)
    assert elapsed >= 30 * 60, f"Expected idle (45min), but elapsed={elapsed/60:.1f}min"
    # Should NOT be 10 minutes (heartbeat message was ignored)
    assert elapsed >= 40 * 60, f"Heartbeat message was not ignored, elapsed={elapsed/60:.1f}min"


@pytest.mark.asyncio
async def test_idle_detection_counts_real_user_messages():
    """Test that heartbeat correctly identifies when user is active."""
    # Create session manager and session
    session_manager = SessionManager(workspace=Path("/tmp/test-heartbeat"))
    session = session_manager.get_or_create("telegram:239824268")

    # Add a real user message 10 minutes ago (recent activity)
    real_user_time = datetime.now() - timedelta(minutes=10)
    session.add_message(
        "user",
        "This is a recent user message",
        sender_id="239824268|testuser",
        timestamp=real_user_time.isoformat()
    )

    # Create heartbeat service with 30 minute idle threshold
    heartbeat = HeartbeatService(
        workspace=Path("/tmp/test-heartbeat"),
        session_manager=session_manager,
        target_session_key="telegram:239824268",
        idle_threshold_s=30 * 60,  # 30 minutes
        interval_s=30 * 60,
        enabled=False
    )

    # Find last user message timestamp
    session = session_manager.get_or_create("telegram:239824268")
    last_user_timestamp = None
    for msg in reversed(session.messages):
        if msg.get("role") == "user":
            sender_id = msg.get("sender_id")
            if sender_id == "user":
                continue
            last_user_timestamp = msg.get("timestamp")
            break

    assert last_user_timestamp is not None
    last_dt = datetime.fromisoformat(last_user_timestamp)
    elapsed = (datetime.now() - last_dt).total_seconds()

    # Should detect user is active (10 minutes < 30 minute threshold)
    assert elapsed < 30 * 60, f"Expected active (10min), but elapsed={elapsed/60:.1f}min"


@pytest.mark.asyncio
async def test_backwards_compat_messages_without_sender_id():
    """Test that old messages without sender_id are treated as real user messages."""
    # Create session manager and session
    session_manager = SessionManager(workspace=Path("/tmp/test-heartbeat"))
    session = session_manager.get_or_create("telegram:239824268")

    # Add an old message without sender_id (backwards compat)
    old_time = datetime.now() - timedelta(minutes=20)
    session.add_message(
        "user",
        "Old message without sender_id",
        timestamp=old_time.isoformat()
    )

    # Find last user message timestamp (should find the old message)
    last_user_timestamp = None
    for msg in reversed(session.messages):
        if msg.get("role") == "user":
            sender_id = msg.get("sender_id")
            if sender_id == "user":
                continue
            last_user_timestamp = msg.get("timestamp")
            break

    assert last_user_timestamp is not None
    last_dt = datetime.fromisoformat(last_user_timestamp)
    elapsed = (datetime.now() - last_dt).total_seconds()

    # Should accept old message (backwards compat)
    assert elapsed < 25 * 60, f"Old message not counted, elapsed={elapsed/60:.1f}min"
