"""
E2E: Hard-Kill Timeout Validation
==================================
Tests that the `--max-runtime-minutes` parameter works as an absolute
hard-kill, deeply breaking the dopamine engine and orchestrator loops.
"""

from datetime import datetime, timedelta

from GramAddict.core.dopamine_engine import DopamineEngine


def test_dopamine_hard_kill_timeout_triggered():
    """
    Verifies that the DopamineEngine correctly interrupts the session
    if the global maximum runtime is exceeded, regardless of baseline boredom.
    """
    engine = DopamineEngine()

    # Baseline: Session should NOT be over
    assert engine.is_app_session_over() is False

    # Inject global limits
    engine.global_start_time = datetime.now()
    engine.global_max_runtime_minutes = 2

    # Should still not be over (we just started)
    assert engine.is_app_session_over() is False

    # Time warp: Simulate 3 minutes passing
    engine.global_start_time = datetime.now() - timedelta(minutes=3)

    # The engine should now trigger a hard kill
    assert engine.is_app_session_over() is True, "DopamineEngine failed to trigger Hard-Kill on timeout!"


def test_goap_hard_kill_timeout_triggered(e2e_device):
    """
    Verifies that the GoalExecutor aborts its planning loop and returns False
    if the global maximum runtime is exceeded.
    """
    from GramAddict.core.goap import GoalExecutor

    # We load a simple home feed XML
    from tests.e2e.conftest import load_fixture_xml

    xml = load_fixture_xml("home_feed_with_ad.xml")
    device = e2e_device([xml, xml, xml])

    # Reset singleton/class variables
    GoalExecutor._instance = None
    GoalExecutor.global_start_time = datetime.now()
    GoalExecutor.global_max_runtime_minutes = 2

    goap = GoalExecutor.get_instance(device, bot_username="testuser")

    # Time warp: Simulate 3 minutes passing
    GoalExecutor.global_start_time = datetime.now() - timedelta(minutes=3)

    try:
        # The achieve loop should immediately exit and return False
        result = goap.achieve("open profile")
        assert result is False, "GoalExecutor failed to abort achieve loop on Hard-Kill timeout!"
    finally:
        GoalExecutor.global_max_runtime_minutes = None
        GoalExecutor.global_start_time = None


def test_workflow_lifecycle_hard_kill(e2e_device, monkeypatch):
    """
    Verifies that the entire bot lifecycle (start_bot) cleanly terminates
    its main 'while True' loop when the global runtime limit is exceeded.
    """
    import argparse

    import GramAddict.core.bot_flow as bot_flow
    from GramAddict.core.config import Config
    from tests.e2e.conftest import load_fixture_xml

    xml = load_fixture_xml("home_feed_with_ad.xml")
    device = e2e_device([xml] * 10)

    # 1. Provide the real emulator to the workflow
    monkeypatch.setattr(bot_flow, "create_device", lambda *args, **kwargs: device)
    monkeypatch.setattr(device, "wake_up", lambda: None, raising=False)
    monkeypatch.setattr(device, "unlock", lambda: None, raising=False)
    monkeypatch.setattr(bot_flow, "verify_and_switch_account", lambda *args, **kwargs: True)

    # 2. Prevent blockers that would hang the CI
    monkeypatch.setattr(bot_flow, "wait_for_next_session", lambda *args: None)
    monkeypatch.setattr(bot_flow, "get_device_info", lambda d: None)
    monkeypatch.setattr(bot_flow, "set_time_delta", lambda args: None)
    monkeypatch.setattr(bot_flow, "open_instagram", lambda d, force_restart=False: True)
    monkeypatch.setattr(bot_flow, "log_metabolic_rate", lambda: None)
    monkeypatch.setattr(bot_flow, "check_if_updated", lambda: None)
    monkeypatch.setattr(bot_flow, "configure_logger", lambda d, u: None)
    monkeypatch.setattr(bot_flow, "check_production_integrity", lambda: None)

    if hasattr(bot_flow, "prewarm_ollama_models"):
        monkeypatch.setattr(bot_flow, "prewarm_ollama_models", lambda cfg: None)
    if hasattr(bot_flow, "check_model_benchmarks"):
        monkeypatch.setattr(bot_flow, "check_model_benchmarks", lambda cfg: None)

    # 3. Prevent inner sub-routines from crashing on non-existent data
    for loop_func in [
        "_run_zero_latency_feed_loop",
        "_run_zero_latency_stories_loop",
        "_run_zero_latency_unfollow_loop",
        "_run_zero_latency_dm_loop",
        "_run_zero_latency_search_loop",
    ]:
        if hasattr(bot_flow, loop_func):
            monkeypatch.setattr(bot_flow, loop_func, lambda *args, **kwargs: "BOREDOM_CHANGE_FEED")

    monkeypatch.setattr(bot_flow.GoalExecutor, "achieve", lambda *args, **kwargs: True)
    monkeypatch.setattr(bot_flow.QNavGraph, "navigate_to", lambda *args, **kwargs: True)
    monkeypatch.setattr(bot_flow.QNavGraph, "do", lambda *args, **kwargs: True)

    # 4. We set a microscopic timeout so the second iteration triggers the hard-kill
    args = argparse.Namespace(
        username="testuser",
        device="emulator-5554",
        app_id="com.instagram.android",
        max_runtime_minutes=0.000001,  # ~60 microseconds
        goal="feed",
        ai_target_audience="",
        blank_start=False,
        working_hours=["00.00-23.59"],
        time_delta_session=0,
        disable_filters=False,
        time_delta=0,
        debug=False,
        device_id="emulator-5554",
    )

    def mock_parse_args(self):
        self.args = args

    monkeypatch.setattr(Config, "parse_args", mock_parse_args)

    # Execute start_bot - it should naturally exit after 1 loop without infinite hanging!
    try:
        bot_flow.start_bot()
    finally:
        bot_flow.GoalExecutor.global_max_runtime_minutes = None
        bot_flow.GoalExecutor.global_start_time = None
        from GramAddict.core.dopamine_engine import DopamineEngine

        DopamineEngine.global_max_runtime_minutes = None
        DopamineEngine.global_start_time = None

    assert True
