from unittest.mock import MagicMock, patch

from GramAddict.core.bot_flow import start_bot


@patch("GramAddict.core.persistent_list.PersistentList.persist")
@patch("secrets.choice", return_value="HomeFeed")
@patch("GramAddict.core.bot_flow._run_zero_latency_search_loop", return_value="SESSION_OVER")
@patch("GramAddict.core.bot_flow._run_zero_latency_dm_loop", return_value="SESSION_OVER")
@patch("GramAddict.core.bot_flow._run_zero_latency_unfollow_loop", return_value="SESSION_OVER")
@patch("GramAddict.core.bot_flow._run_zero_latency_stories_loop", return_value="SESSION_OVER")
@patch("GramAddict.core.bot_flow._run_zero_latency_feed_loop", return_value="SESSION_OVER")
@patch("GramAddict.core.bot_flow.DojoEngine")
@patch("GramAddict.core.bot_flow.HoneypotRadome")
@patch("GramAddict.core.bot_flow.ParasocialCRMDB")
@patch("GramAddict.core.bot_flow.GrowthBrain")
@patch("GramAddict.core.bot_flow.ResonanceEngine")
@patch("GramAddict.core.bot_flow.DopamineEngine")
@patch("GramAddict.core.bot_flow.ZeroLatencyEngine")
@patch("GramAddict.core.bot_flow.QNavGraph")
@patch("GramAddict.core.bot_flow.TelepathicEngine")
@patch("GramAddict.core.bot_flow.dump_ui_state")
@patch("GramAddict.core.bot_flow.random_sleep")
@patch("GramAddict.core.bot_flow.close_instagram")
@patch("GramAddict.core.bot_flow.get_instagram_version", return_value="1.0")
@patch("GramAddict.core.bot_flow.open_instagram", return_value=True)
@patch("GramAddict.core.bot_flow.SessionState")
@patch("GramAddict.core.bot_flow.set_time_delta")
@patch("GramAddict.core.bot_flow.create_device")
@patch("GramAddict.core.llm_provider.log_openrouter_burn")
@patch("GramAddict.core.benchmark_guard.check_model_benchmarks")
@patch("GramAddict.core.bot_flow.check_if_updated")
@patch("GramAddict.core.bot_flow.configure_logger")
@patch("GramAddict.core.bot_flow.Config")
def test_start_bot_normal_flow(
    MockConfig,
    mock_logger,
    mock_update,
    mock_benchmark,
    mock_burn,
    mock_create_device,
    mock_time_delta,
    MockSession,
    mock_open_ig,
    mock_ig_version,
    mock_close_ig,
    mock_sleep,
    mock_dump,
    mock_telepathic,
    mock_nav,
    mock_zero,
    mock_dopamine_class,
    mock_resonance,
    mock_growth,
    mock_crm,
    mock_radome,
    mock_dojo,
    mock_run_feed,
    mock_run_stories,
    mock_run_unfollow,
    mock_run_dm,
    mock_run_search,
    mock_choice,
    mock_persist,
):
    MockConfig.return_value.args.username = "test"
    MockConfig.return_value.args.feed = True
    MockConfig.return_value.args.explore = False
    MockConfig.return_value.args.reels = True
    MockConfig.return_value.args.stories = False
    MockConfig.return_value.args.capture_e2e_dumps = False
    MockConfig.return_value.args.working_hours = [10, 20]
    MockConfig.return_value.args.time_delta_session = 30

    device = mock_create_device.return_value
    device.dump_hierarchy.return_value = '<?xml version="1.0" encoding="UTF-8" ?><hierarchy><node resource-id="com.instagram.android:id/action_bar_title" text="test" /></hierarchy>'
    mock_nav.return_value.navigate_to.return_value = True
    mock_nav.return_value.do.return_value = True

    MockSession.inside_working_hours.return_value = (True, 0)

    # Simulate dopamine session over after one loop
    mock_dopamine = mock_dopamine_class.return_value
    mock_dopamine.is_app_session_over.side_effect = [False, True]
    mock_dopamine.boredom = 10.0

    # We need to intentionally throw an exception to break the "while True" loop
    MockSession.side_effect = [MagicMock(), Exception("Break infinite loop")]

    try:
        start_bot(username="test", device_id="123")
    except Exception as e:
        if str(e) != "Break infinite loop":
            raise e

    assert mock_run_feed.called
