"""Unit tests for LinearLocalReader cache refresh and failure-resilience logic."""

from unittest.mock import MagicMock

from oh_my_linear.reader import CachedData, LinearLocalReader


class TestCacheDataStructure:
    """Tests for CachedData structure and initialization."""

    def test_cached_data_default_fields(self):
        """CachedData initializes with empty collections."""
        cache = CachedData()
        assert cache.teams == {}
        assert cache.users == {}
        assert cache.issues == {}
        assert cache.comments == {}
        assert cache.projects == {}
        assert cache.loaded_at == 0.0

    def test_cached_data_with_sample_data(self):
        """CachedData can store teams and users."""
        cache = CachedData(
            teams={"t1": {"id": "t1", "name": "Team 1"}},
            users={"u1": {"id": "u1", "name": "User 1"}},
        )
        assert cache.teams["t1"]["name"] == "Team 1"
        assert cache.users["u1"]["name"] == "User 1"


class TestReaderInitialization:
    """Tests for LinearLocalReader initialization."""

    def test_reader_initializes_with_default_cache(self):
        """LinearLocalReader initializes with empty CachedData."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        assert isinstance(reader._cache, CachedData)
        assert reader._cache.teams == {}

    def test_reader_stores_db_paths(self):
        """LinearLocalReader stores db_path and blob_path."""
        db = "/test/db"
        blob = "/test/blob"
        reader = LinearLocalReader(db_path=db, blob_path=blob)
        assert reader._db_path == db
        assert reader._blob_path == blob


class TestRefreshCacheAlwaysReloads:
    """Tests that refresh_cache() always calls _reload_cache."""

    def test_refresh_cache_calls_reload(self):
        """refresh_cache() always calls _reload_cache."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        reader._reload_cache = MagicMock()

        reader.refresh_cache()

        reader._reload_cache.assert_called_once()

    def test_multiple_refresh_calls(self):
        """Multiple refresh_cache() calls each trigger _reload_cache."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        reader._reload_cache = MagicMock()

        reader.refresh_cache()
        reader.refresh_cache()
        reader.refresh_cache()

        assert reader._reload_cache.call_count == 3


class TestFailurePreservesPreviousCache:
    """Tests that _reload_cache failure preserves previous cache."""

    def test_reload_failure_keeps_previous_cache(self):
        """When _reload_cache fails, self._cache is preserved."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")

        # Set up a known previous cache
        previous_cache = CachedData(
            loaded_at=1000.0,
            teams={"t1": {"id": "t1", "name": "Team 1"}},
        )
        reader._cache = previous_cache

        # Call refresh_cache which will fail because db_path doesn't exist
        reader.refresh_cache()

        # Previous cache should be preserved
        assert reader._cache.teams == {"t1": {"id": "t1", "name": "Team 1"}}
        assert reader._cache.loaded_at == 1000.0

    def test_reload_failure_sets_degraded(self):
        """When _reload_cache fails, health is set to degraded."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")

        previous_cache = CachedData(
            loaded_at=1000.0,
            teams={"t1": {"id": "t1"}},
        )
        reader._cache = previous_cache

        reader.refresh_cache()

        assert reader.is_degraded() is True


class TestPropertiesReturnCacheDirectly:
    """Tests that properties return self._cache fields directly."""

    def test_teams_property(self):
        """Teams property returns self._cache.teams."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        reader._cache = CachedData(teams={"t1": {"id": "t1"}})
        assert reader.teams == {"t1": {"id": "t1"}}

    def test_users_property(self):
        """Users property returns self._cache.users."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        reader._cache = CachedData(users={"u1": {"id": "u1"}})
        assert reader.users == {"u1": {"id": "u1"}}

    def test_issues_property(self):
        """Issues property returns self._cache.issues."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        reader._cache = CachedData(issues={"i1": {"id": "i1"}})
        assert reader.issues == {"i1": {"id": "i1"}}

    def test_empty_cache_returns_empty(self):
        """Properties return empty dicts from default cache."""
        reader = LinearLocalReader(db_path="/nonexistent", blob_path="/nonexistent")
        assert reader.teams == {}
        assert reader.users == {}
        assert reader.issues == {}
