"""Tests for globals.py — gap coverage.

Covers the three functions with zero test coverage:
- get_usernames_with_active_research
- is_research_thread_alive
- update_progress_and_check_active
"""

from unittest.mock import Mock

import pytest

from local_deep_research.web.routes import globals as g


@pytest.fixture(autouse=True)
def _clean_globals():
    """Reset all global state before each test."""
    with g._lock:
        g._active_research.clear()
        g._termination_flags.clear()
    yield
    with g._lock:
        g._active_research.clear()
        g._termination_flags.clear()


# ===================================================================
# get_usernames_with_active_research
# ===================================================================


class TestGetUsernamesWithActiveResearch:
    def test_empty_returns_empty_set(self):
        assert g.get_usernames_with_active_research() == set()

    def test_entry_with_username(self):
        g.set_active_research("r1", {"settings": {"username": "alice"}})
        assert g.get_usernames_with_active_research() == {"alice"}

    def test_entry_with_username_none_filtered(self):
        g.set_active_research("r1", {"settings": {"username": None}})
        assert g.get_usernames_with_active_research() == set()

    def test_entry_with_no_settings_key(self):
        g.set_active_research("r1", {"progress": 0})
        assert g.get_usernames_with_active_research() == set()

    def test_duplicate_usernames_deduplicated(self):
        g.set_active_research("r1", {"settings": {"username": "alice"}})
        g.set_active_research("r2", {"settings": {"username": "alice"}})
        assert g.get_usernames_with_active_research() == {"alice"}

    def test_different_usernames(self):
        g.set_active_research("r1", {"settings": {"username": "alice"}})
        g.set_active_research("r2", {"settings": {"username": "bob"}})
        assert g.get_usernames_with_active_research() == {"alice", "bob"}


# ===================================================================
# is_research_thread_alive
# ===================================================================


class TestIsResearchThreadAlive:
    def test_unknown_research_id(self):
        assert g.is_research_thread_alive("r1") is False

    def test_entry_with_no_thread_key(self):
        g.set_active_research("r1", {"progress": 0})
        assert g.is_research_thread_alive("r1") is False

    def test_entry_with_thread_none(self):
        g.set_active_research("r1", {"thread": None})
        assert g.is_research_thread_alive("r1") is False

    def test_thread_alive(self):
        mock_thread = Mock()
        mock_thread.is_alive.return_value = True
        g.set_active_research("r1", {"thread": mock_thread})
        assert g.is_research_thread_alive("r1") is True

    def test_thread_dead(self):
        mock_thread = Mock()
        mock_thread.is_alive.return_value = False
        g.set_active_research("r1", {"thread": mock_thread})
        assert g.is_research_thread_alive("r1") is False


# ===================================================================
# update_progress_and_check_active
# ===================================================================


class TestUpdateProgressAndCheckActive:
    def test_not_found(self):
        assert g.update_progress_and_check_active("r1", 50) == (None, False)

    def test_new_progress_higher_updates(self):
        g.set_active_research("r1", {"progress": 10})
        result = g.update_progress_and_check_active("r1", 50)
        assert result == (50, True)
        assert g.get_research_field("r1", "progress") == 50

    def test_new_progress_lower_no_update(self):
        g.set_active_research("r1", {"progress": 80})
        result = g.update_progress_and_check_active("r1", 50)
        assert result == (80, True)
        assert g.get_research_field("r1", "progress") == 80

    def test_new_progress_equal_no_update(self):
        g.set_active_research("r1", {"progress": 50})
        result = g.update_progress_and_check_active("r1", 50)
        assert result == (50, True)

    def test_new_progress_none(self):
        g.set_active_research("r1", {"progress": 30})
        result = g.update_progress_and_check_active("r1", None)
        assert result == (30, True)

    def test_no_progress_key_defaults_to_zero(self):
        g.set_active_research("r1", {})
        result = g.update_progress_and_check_active("r1", 10)
        assert result == (10, True)
        assert g.get_research_field("r1", "progress") == 10
