from unittest.mock import patch

import pytest

from app.services.naming import (
    get_naming_categories,
    get_words_for_category,
    suggest_names,
)

MOCK_DICTIONARY = {
    "mythology": ["Apollo", "Athena", "Loki", "Thor", "Zeus"],
    "food": ["Basil", "Sage", "Pepper", "Saffron", "Mango"],
    "space": ["Apollo", "Nova", "Nebula", "Comet", "Vega"],
}


@pytest.fixture(autouse=True)
def _mock_dictionary():
    with patch("app.services.naming._load_dictionary", return_value=MOCK_DICTIONARY):
        yield


class TestGetNamingCategories:
    def test_returns_sorted_categories(self):
        result = get_naming_categories()
        assert result == ["food", "mythology", "space"]

    def test_returns_empty_for_empty_dictionary(self):
        with patch("app.services.naming._load_dictionary", return_value={}):
            assert get_naming_categories() == []


class TestGetWordsForCategory:
    def test_returns_words_for_valid_category(self):
        result = get_words_for_category("mythology")
        assert result == ["Apollo", "Athena", "Loki", "Thor", "Zeus"]

    def test_returns_empty_for_unknown_category(self):
        assert get_words_for_category("nonexistent") == []


class TestSuggestNames:
    def test_returns_requested_count(self):
        result = suggest_names("mythology", set(), count=3)
        assert len(result) == 3
        assert all(name in MOCK_DICTIONARY["mythology"] for name in result)

    def test_excludes_used_names(self):
        used = {"Apollo", "Athena", "Loki"}
        result = suggest_names("mythology", used, count=10)
        assert set(result) <= {"Thor", "Zeus"}
        assert not set(result) & used

    def test_returns_fewer_when_category_nearly_exhausted(self):
        used = {"Apollo", "Athena", "Loki", "Thor"}
        result = suggest_names("mythology", used, count=10)
        assert result == ["Zeus"]

    def test_returns_empty_when_category_fully_exhausted(self):
        used = {"Apollo", "Athena", "Loki", "Thor", "Zeus"}
        result = suggest_names("mythology", used, count=10)
        assert result == []

    def test_returns_empty_for_unknown_category(self):
        result = suggest_names("nonexistent", set(), count=10)
        assert result == []

    def test_no_duplicates_in_suggestions(self):
        result = suggest_names("mythology", set(), count=5)
        assert len(result) == len(set(result))

    def test_default_count_is_ten(self):
        # food has 5 words, so we should get all 5
        result = suggest_names("food", set())
        assert len(result) == 5

    def test_cross_category_names_handled_independently(self):
        # "Apollo" used in mythology shouldn't affect space
        used = {"Apollo"}
        mythology_result = suggest_names("mythology", used, count=10)
        space_result = suggest_names("space", used, count=10)
        assert "Apollo" not in mythology_result
        assert "Apollo" not in space_result
