"""Unit tests for MenuService."""

import pytest

from app.modules.core.services.menu_service import MenuService
from app.modules.enums import FrontendType


@pytest.mark.unit
@pytest.mark.core
class TestMenuService:
    """Test suite for MenuService."""

    def setup_method(self):
        self.service = MenuService()

    def test_service_instantiation(self):
        """Service can be instantiated."""
        assert self.service is not None


@pytest.mark.unit
@pytest.mark.core
class TestMenuServiceMerchantRendering:
    """Test get_menu_for_rendering with FrontendType.MERCHANT and enabled_module_codes."""

    def setup_method(self):
        self.service = MenuService()

    def test_render_merchant_menu_all_modules(self, db):
        """Rendering with all modules shows all sections."""
        enabled = {"core", "billing", "tenancy", "loyalty"}
        sections = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes=enabled,
        )
        section_ids = {s.id for s in sections}
        assert "main" in section_ids
        assert "billing" in section_ids
        assert "account" in section_ids
        assert "loyalty" in section_ids

    def test_render_merchant_menu_without_loyalty(self, db):
        """Rendering without loyalty module hides loyalty section."""
        enabled = {"core", "billing", "tenancy"}
        sections = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes=enabled,
        )
        section_ids = {s.id for s in sections}
        assert "loyalty" not in section_ids
        assert "main" in section_ids
        assert "billing" in section_ids

    def test_render_merchant_menu_section_item_structure(self, db):
        """Each section has items with expected attributes."""
        enabled = {"core", "billing", "tenancy", "loyalty"}
        sections = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes=enabled,
        )
        for section in sections:
            assert section.id
            assert len(section.items) > 0
            for item in section.items:
                assert item.id
                assert item.label_key
                assert item.icon
                assert item.route
                assert item.route.startswith("/merchants/")

    def test_render_merchant_menu_section_ordering(self, db):
        """Sections are returned in correct order."""
        enabled = {"core", "billing", "tenancy", "loyalty"}
        sections = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes=enabled,
        )
        orders = [s.order for s in sections]
        assert orders == sorted(orders)

    def test_render_merchant_menu_no_enabled_modules_returns_nothing(self, db):
        """With empty enabled set, no sections are returned."""
        sections = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes=set(),
        )
        assert len(sections) == 0

    def test_enabled_module_codes_propagated(self, db):
        """enabled_module_codes parameter is properly propagated to discovery service."""
        # With loyalty
        with_loyalty = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes={"core", "billing", "tenancy", "loyalty"},
        )
        # Without loyalty
        without_loyalty = self.service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.MERCHANT,
            enabled_module_codes={"core", "billing", "tenancy"},
        )
        with_ids = {s.id for s in with_loyalty}
        without_ids = {s.id for s in without_loyalty}
        assert "loyalty" in with_ids
        assert "loyalty" not in without_ids


@pytest.mark.unit
@pytest.mark.core
class TestMenuServiceMerchantByPlatform:
    """Test get_merchant_menu_by_platform grouping logic."""

    def setup_method(self):
        self.service = MenuService()

    def test_core_sections_contain_only_core_items(self, db):
        """Core sections should only have items from core modules."""
        from app.modules.core.services.menu_discovery_service import (
            menu_discovery_service,
        )
        from app.modules.registry import MODULES

        core_codes = {code for code, mod in MODULES.items() if mod.is_core}

        core_sections = menu_discovery_service.get_menu_sections_for_frontend(
            db,
            FrontendType.MERCHANT,
            enabled_module_codes=core_codes,
        )
        for section in core_sections:
            section.items = [i for i in section.items if i.module_code in core_codes]

        for section in core_sections:
            for item in section.items:
                assert item.module_code in core_codes, (
                    f"Non-core item '{item.id}' (module={item.module_code}) "
                    f"found in core section '{section.id}'"
                )

    def test_non_core_sections_for_loyalty(self, db):
        """Non-core modules like loyalty produce merchant menu sections."""
        from app.modules.core.services.menu_discovery_service import (
            menu_discovery_service,
        )
        from app.modules.registry import MODULES

        core_codes = {code for code, mod in MODULES.items() if mod.is_core}
        non_core = {"loyalty"}

        sections = menu_discovery_service.get_menu_sections_for_frontend(
            db,
            FrontendType.MERCHANT,
            enabled_module_codes=non_core,
        )
        sections = [
            s
            for s in sections
            if any(i.module_code in non_core for i in s.items)
        ]

        assert len(sections) > 0, "Loyalty module should produce merchant menu sections"
        for section in sections:
            for item in section.items:
                assert item.module_code not in core_codes
