# tests/unit/modules/loyalty/test_loyalty_features.py
"""
Unit tests for the loyalty feature provider.

Tests cover:
- Feature category
- Feature declarations (count, codes, types, scopes)
- Usage methods return empty lists
- Protocol compliance
"""

import pytest

from app.modules.contracts.features import (
    FeatureProviderProtocol,
    FeatureScope,
    FeatureType,
)
from app.modules.loyalty.definition import loyalty_module
from app.modules.loyalty.services.loyalty_features import (
    LoyaltyFeatureProvider,
    loyalty_feature_provider,
)


@pytest.mark.unit
class TestLoyaltyFeatureProvider:
    """Tests for LoyaltyFeatureProvider."""

    def test_feature_category(self):
        """Feature category should be 'loyalty'."""
        assert loyalty_feature_provider.feature_category == "loyalty"

    def test_get_feature_declarations_count(self):
        """Should return exactly 11 feature declarations."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        assert len(declarations) == 11

    def test_feature_codes_match_module_definition(self):
        """All declared feature codes should match loyalty_module.features."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        declared_codes = {d.code for d in declarations}
        module_features = set(loyalty_module.features)
        assert declared_codes == module_features

    def test_all_features_are_binary(self):
        """All loyalty features should be BINARY type."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        for decl in declarations:
            assert decl.feature_type == FeatureType.BINARY, (
                f"Feature {decl.code} should be BINARY, got {decl.feature_type}"
            )

    def test_all_features_are_merchant_scoped(self):
        """All loyalty features should be MERCHANT scoped."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        for decl in declarations:
            assert decl.scope == FeatureScope.MERCHANT, (
                f"Feature {decl.code} should be MERCHANT scoped, got {decl.scope}"
            )

    def test_all_features_have_name_key(self):
        """All features should have a non-empty name_key."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        for decl in declarations:
            assert decl.name_key, f"Feature {decl.code} missing name_key"

    def test_all_features_have_description_key(self):
        """All features should have a non-empty description_key."""
        declarations = loyalty_feature_provider.get_feature_declarations()
        for decl in declarations:
            assert decl.description_key, f"Feature {decl.code} missing description_key"

    def test_get_store_usage_returns_empty(self):
        """get_store_usage should return an empty list."""
        result = loyalty_feature_provider.get_store_usage(db=None, store_id=1)
        assert result == []

    def test_get_merchant_usage_returns_empty(self):
        """get_merchant_usage should return an empty list."""
        result = loyalty_feature_provider.get_merchant_usage(
            db=None, merchant_id=1, platform_id=1
        )
        assert result == []

    def test_satisfies_feature_provider_protocol(self):
        """Provider should satisfy FeatureProviderProtocol."""
        assert isinstance(loyalty_feature_provider, FeatureProviderProtocol)

    def test_singleton_is_correct_type(self):
        """Singleton instance should be a LoyaltyFeatureProvider."""
        assert isinstance(loyalty_feature_provider, LoyaltyFeatureProvider)
