"""Tests for MemoryCategory, TTLTier, TTL mappings, and utility functions."""

from __future__ import annotations

import pytest

from claude_engram.categories import (
    CATEGORY_TTL,
    TTL_MAP,
    MemoryCategory,
    TTLTier,
    get_ttl_seconds,
    validate_category,
)


class TestMemoryCategory:
    """Tests for MemoryCategory enum."""

    def test_has_twelve_values(self) -> None:
        assert len(MemoryCategory) == 12

    def test_enum_values(self) -> None:
        expected = {
            "file_ownership",
            "interface",
            "query_cache",
            "lesson",
            "checkpoint",
            "session_summary",
            "decision",
            "worker_msg",  # Inter-worker communication (#52)
            # Phase 6: Agent Coordination categories
            "file_claim",
            "interface_broadcast",
            "coordination_event",
            # H9: Passive capture
            "idea",
        }
        actual = {c.value for c in MemoryCategory}
        assert actual == expected

    def test_is_str_enum(self) -> None:
        for cat in MemoryCategory:
            assert isinstance(cat, str)
            assert cat == cat.value


class TestTTLTier:
    """Tests for TTLTier enum."""

    def test_has_five_values(self) -> None:
        assert len(TTLTier) == 5

    def test_enum_values(self) -> None:
        expected = {"ephemeral", "short", "volatile", "session", "permanent"}
        actual = {t.value for t in TTLTier}
        assert actual == expected

    def test_is_str_enum(self) -> None:
        for tier in TTLTier:
            assert isinstance(tier, str)


class TestCategoryTTLMapping:
    """Tests for CATEGORY_TTL dict mapping all 7 categories to tiers."""

    def test_all_categories_mapped(self) -> None:
        for cat in MemoryCategory:
            assert cat in CATEGORY_TTL, f"{cat} not in CATEGORY_TTL"

    def test_file_ownership_is_session(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.FILE_OWNERSHIP] == TTLTier.SESSION

    def test_interface_is_session(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.INTERFACE] == TTLTier.SESSION

    def test_query_cache_is_ephemeral(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.QUERY_CACHE] == TTLTier.EPHEMERAL

    def test_lesson_is_permanent(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.LESSON] == TTLTier.PERMANENT

    def test_checkpoint_is_volatile(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.CHECKPOINT] == TTLTier.VOLATILE

    def test_session_summary_is_session(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.SESSION_SUMMARY] == TTLTier.SESSION

    def test_decision_is_session(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.DECISION] == TTLTier.SESSION

    def test_worker_msg_is_short(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.WORKER_MSG] == TTLTier.SHORT


class TestTTLMap:
    """Tests for TTL_MAP dict mapping tiers to seconds."""

    def test_all_tiers_mapped(self) -> None:
        for tier in TTLTier:
            assert tier in TTL_MAP, f"{tier} not in TTL_MAP"

    def test_ephemeral_is_300(self) -> None:
        assert TTL_MAP[TTLTier.EPHEMERAL] == 300

    def test_short_is_1800(self) -> None:
        assert TTL_MAP[TTLTier.SHORT] == 1800

    def test_volatile_is_14400(self) -> None:
        assert TTL_MAP[TTLTier.VOLATILE] == 14400

    def test_session_is_604800(self) -> None:
        assert TTL_MAP[TTLTier.SESSION] == 604800

    def test_permanent_is_none(self) -> None:
        assert TTL_MAP[TTLTier.PERMANENT] is None


class TestGetTTLSeconds:
    """Tests for get_ttl_seconds() function."""

    def test_ephemeral_category(self) -> None:
        assert get_ttl_seconds(MemoryCategory.QUERY_CACHE) == 300

    def test_short_category(self) -> None:
        assert get_ttl_seconds(MemoryCategory.WORKER_MSG) == 1800

    def test_volatile_category(self) -> None:
        assert get_ttl_seconds(MemoryCategory.CHECKPOINT) == 14400

    def test_session_category(self) -> None:
        assert get_ttl_seconds(MemoryCategory.FILE_OWNERSHIP) == 604800

    def test_permanent_category(self) -> None:
        assert get_ttl_seconds(MemoryCategory.LESSON) is None

    def test_all_categories_return_valid(self) -> None:
        for cat in MemoryCategory:
            result = get_ttl_seconds(cat)
            assert result is None or isinstance(result, int)


class TestValidateCategory:
    """Tests for validate_category() function."""

    def test_valid_category_lowercase(self) -> None:
        result = validate_category("lesson")
        assert result == MemoryCategory.LESSON

    def test_valid_category_mixed_case(self) -> None:
        result = validate_category("LESSON")
        assert result == MemoryCategory.LESSON

    def test_valid_category_with_whitespace(self) -> None:
        result = validate_category("  decision  ")
        assert result == MemoryCategory.DECISION

    def test_general_legacy_passthrough(self) -> None:
        result = validate_category("general")
        assert result == "general"
        assert isinstance(result, str)
        assert not isinstance(result, MemoryCategory)

    def test_general_case_insensitive(self) -> None:
        result = validate_category("General")
        assert result == "general"

    def test_unknown_category_raises(self) -> None:
        with pytest.raises(ValueError, match="Unknown category"):
            validate_category("not_a_category")

    def test_empty_string_raises(self) -> None:
        with pytest.raises(ValueError):
            validate_category("totally_bogus")

    def test_all_enum_values_valid(self) -> None:
        for cat in MemoryCategory:
            result = validate_category(cat.value)
            assert result == cat


class TestCrossWindowCategories:
    """Tests for CROSS_WINDOW_CATEGORIES frozenset."""

    def test_is_frozenset(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        assert isinstance(CROSS_WINDOW_CATEGORIES, frozenset)

    def test_contains_exactly_seven_categories(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        expected = {
            "decision",
            "lesson",
            "interface",
            "session_summary",
            "interface_broadcast",  # Phase 6
            "coordination_event",  # Phase 6
            "idea",  # H9: Passive capture
        }
        assert expected == CROSS_WINDOW_CATEGORIES

    def test_does_not_contain_checkpoint(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        assert "checkpoint" not in CROSS_WINDOW_CATEGORIES

    def test_does_not_contain_file_ownership(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        assert "file_ownership" not in CROSS_WINDOW_CATEGORIES

    def test_does_not_contain_query_cache(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        assert "query_cache" not in CROSS_WINDOW_CATEGORIES


class TestIdeaCategory:
    """H9: Tests for the 'idea' category for passive capture."""

    def test_idea_enum_exists(self) -> None:
        assert MemoryCategory.IDEA == "idea"

    def test_idea_ttl_is_session(self) -> None:
        assert CATEGORY_TTL[MemoryCategory.IDEA] == TTLTier.SESSION

    def test_idea_ttl_seconds_is_seven_days(self) -> None:
        assert get_ttl_seconds(MemoryCategory.IDEA) == 604800

    def test_idea_in_cross_window(self) -> None:
        from claude_engram.categories import CROSS_WINDOW_CATEGORIES

        assert "idea" in CROSS_WINDOW_CATEGORIES

    def test_idea_validates(self) -> None:
        result = validate_category("idea")
        assert result == MemoryCategory.IDEA

    def test_idea_validates_case_insensitive(self) -> None:
        result = validate_category("IDEA")
        assert result == MemoryCategory.IDEA
