"""Tests for the cache module."""

from __future__ import annotations

import time
from pathlib import Path

import pytest

from bandito.cache import DiskCache, get_cache, reset_cache


class TestDiskCache:
    def test_set_and_get(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path)
        cache.set("project", {"key": "value"}, {"data": "test"})

        result, is_stale = cache.get("project", {"key": "value"})
        assert result == {"data": "test"}
        assert is_stale is False

    def test_miss_returns_none(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path)
        result, is_stale = cache.get("project", {"missing": True})
        assert result is None
        assert is_stale is False

    def test_stale_after_ttl(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path, ttl=1)
        cache.set("project", {"key": "value"}, {"data": "test"})

        result, is_stale = cache.get("project", {"key": "value"})
        assert result == {"data": "test"}
        assert is_stale is False

        time.sleep(1.5)

        result, is_stale = cache.get("project", {"key": "value"})
        assert result == {"data": "test"}
        assert is_stale is True

    def test_delete_entry(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path)
        cache.set("project", {"key": "value"}, {"data": "test"})

        result, _ = cache.get("project", {"key": "value"})
        assert result is not None

        cache.delete("project", {"key": "value"})

        result, _ = cache.get("project", {"key": "value"})
        assert result is None

    def test_invalidate_project(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path)
        cache.set("project", {"key1": "a"}, {"data": "1"})
        cache.set("project", {"key2": "b"}, {"data": "2"})

        result1, _ = cache.get("project", {"key1": "a"})
        result2, _ = cache.get("project", {"key2": "b"})
        assert result1 is not None
        assert result2 is not None

        cache.invalidate_project("project")

        result1, _ = cache.get("project", {"key1": "a"})
        result2, _ = cache.get("project", {"key2": "b"})
        assert result1 is None
        assert result2 is None

    def test_cleanup_removes_expired(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path, ttl=1)
        cache.set("project", {"key": "value"}, {"data": "test"})

        time.sleep(2.5)

        removed = cache.cleanup()
        assert removed >= 1

        result, _ = cache.get("project", {"key": "value"})
        assert result is None

    def test_different_projects_separate(self, tmp_path: Path):
        cache = DiskCache(cache_dir=tmp_path)
        cache.set("proj1", {"key": "value"}, {"data": "1"})
        cache.set("proj2", {"key": "value"}, {"data": "2"})

        result1, _ = cache.get("proj1", {"key": "value"})
        result2, _ = cache.get("proj2", {"key": "value"})

        assert result1 == {"data": "1"}
        assert result2 == {"data": "2"}


class TestGetCache:
    def test_global_cache_instance(self):
        reset_cache()
        cache1 = get_cache()
        cache2 = get_cache()
        assert cache1 is cache2

    def test_reset_cache(self):
        reset_cache()
        cache1 = get_cache()
        reset_cache()
        cache2 = get_cache()
        assert cache1 is not cache2
