# tests/integration/api/v1/modules/test_module_access.py
"""
Integration tests for module-based access control.

Tests verify that:
- Disabled modules return 403 Forbidden
- Enabled modules allow access
- Core modules are always accessible
- Module dependencies are enforced
"""

import pytest

from app.modules.tenancy.models import Platform


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.modules
class TestModuleAccessControl:
    """Tests for module-based access control on API endpoints."""

    # ========================================================================
    # Billing Module Access Tests
    # ========================================================================

    def test_billing_accessible_when_enabled(
        self, client, auth_headers, test_vendor, db
    ):
        """Test billing endpoints accessible when module enabled."""
        # Ensure billing module is enabled (default - no config means all enabled)
        response = client.get(
            "/api/v1/vendor/billing/subscription",
            headers=auth_headers,
        )

        # Should succeed (200) or have other error, but NOT 403 for module
        assert response.status_code != 403 or "module" not in response.json().get("message", "").lower()

    def test_billing_forbidden_when_disabled(
        self, client, auth_headers, test_vendor, db, test_platform
    ):
        """Test billing endpoints return 403 when module disabled."""
        # Disable billing module
        test_platform.settings = {"enabled_modules": ["core", "platform-admin", "inventory"]}
        db.commit()

        response = client.get(
            "/api/v1/vendor/billing/subscription",
            headers=auth_headers,
        )

        # Should return 403 with module disabled message
        assert response.status_code == 403
        data = response.json()
        assert "module" in data.get("message", "").lower() or data.get("error_code") == "MODULE_DISABLED"

    # ========================================================================
    # Inventory Module Access Tests
    # ========================================================================

    def test_inventory_accessible_when_enabled(
        self, client, auth_headers, test_inventory
    ):
        """Test inventory endpoints accessible when module enabled."""
        response = client.get(
            "/api/v1/vendor/inventory",
            headers=auth_headers,
        )

        # Should succeed
        assert response.status_code == 200

    def test_inventory_forbidden_when_disabled(
        self, client, auth_headers, db, test_platform
    ):
        """Test inventory endpoints return 403 when module disabled."""
        # Disable inventory module
        test_platform.settings = {"enabled_modules": ["core", "platform-admin", "billing"]}
        db.commit()

        response = client.get(
            "/api/v1/vendor/inventory",
            headers=auth_headers,
        )

        # Should return 403
        assert response.status_code == 403
        data = response.json()
        assert "module" in data.get("message", "").lower() or data.get("error_code") == "MODULE_DISABLED"

    # ========================================================================
    # Orders Module Access Tests
    # ========================================================================

    def test_orders_accessible_when_enabled(
        self, client, auth_headers, test_order
    ):
        """Test orders endpoints accessible when module enabled."""
        response = client.get(
            "/api/v1/vendor/orders",
            headers=auth_headers,
        )

        # Should succeed
        assert response.status_code == 200

    def test_orders_forbidden_when_disabled(
        self, client, auth_headers, db, test_platform
    ):
        """Test orders endpoints return 403 when module disabled."""
        # Disable orders module
        test_platform.settings = {"enabled_modules": ["core", "platform-admin"]}
        db.commit()

        response = client.get(
            "/api/v1/vendor/orders",
            headers=auth_headers,
        )

        # Should return 403
        assert response.status_code == 403

    # ========================================================================
    # Marketplace Module Access Tests
    # ========================================================================

    def test_marketplace_accessible_when_enabled(
        self, client, auth_headers
    ):
        """Test marketplace endpoints accessible when module enabled."""
        response = client.get(
            "/api/v1/vendor/marketplace/settings",
            headers=auth_headers,
        )

        # Should not return 403 for module disabled
        # (might be 404 if no settings exist, or 200)
        assert response.status_code != 403 or "module" not in response.json().get("message", "").lower()

    def test_marketplace_forbidden_when_disabled(
        self, client, auth_headers, db, test_platform
    ):
        """Test marketplace endpoints return 403 when module disabled."""
        # Disable marketplace module but keep inventory (its dependency)
        test_platform.settings = {"enabled_modules": ["core", "platform-admin", "inventory"]}
        db.commit()

        response = client.get(
            "/api/v1/vendor/marketplace/settings",
            headers=auth_headers,
        )

        # Should return 403
        assert response.status_code == 403

    # ========================================================================
    # Core Module Tests
    # ========================================================================

    def test_core_always_accessible(
        self, client, auth_headers, db, test_platform
    ):
        """Test core endpoints always accessible even with empty modules."""
        # Set empty module list (but core is always added)
        test_platform.settings = {"enabled_modules": []}
        db.commit()

        # Dashboard is a core endpoint
        response = client.get(
            "/api/v1/vendor/dashboard",
            headers=auth_headers,
        )

        # Should NOT return 403 for module disabled
        assert response.status_code != 403 or "module" not in response.json().get("message", "").lower()

    # ========================================================================
    # Admin Module Access Tests
    # ========================================================================

    def test_admin_inventory_accessible_when_enabled(
        self, client, admin_headers, test_inventory
    ):
        """Test admin inventory endpoints accessible when module enabled."""
        response = client.get(
            "/api/v1/admin/inventory",
            headers=admin_headers,
        )

        # Should succeed
        assert response.status_code == 200

    def test_admin_inventory_forbidden_when_disabled(
        self, client, admin_headers, db, test_platform
    ):
        """Test admin inventory endpoints return 403 when module disabled."""
        # Disable inventory module
        test_platform.settings = {"enabled_modules": ["core", "platform-admin"]}
        db.commit()

        response = client.get(
            "/api/v1/admin/inventory",
            headers=admin_headers,
        )

        # Should return 403
        assert response.status_code == 403


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.modules
class TestModuleDependencyAccess:
    """Tests for module dependency enforcement in access control."""

    def test_marketplace_requires_inventory(
        self, client, auth_headers, db, test_platform
    ):
        """Test marketplace requires inventory to be enabled."""
        # Enable marketplace but disable inventory
        test_platform.settings = {"enabled_modules": ["marketplace"]}
        db.commit()

        # Due to dependency resolution, inventory should be auto-enabled
        response = client.get(
            "/api/v1/vendor/inventory",
            headers=auth_headers,
        )

        # Should be accessible because marketplace depends on inventory
        # The module service should auto-enable inventory
        assert response.status_code != 403 or "module" not in response.json().get("message", "").lower()

    def test_disabling_dependency_disables_dependent(
        self, client, auth_headers, db, test_platform
    ):
        """Test that disabling a dependency also affects dependent modules."""
        # First enable both
        test_platform.settings = {"enabled_modules": ["inventory", "marketplace"]}
        db.commit()

        # Now disable inventory - marketplace should also be affected
        test_platform.settings = {"enabled_modules": []}  # Only core remains
        db.commit()

        # Marketplace should be disabled
        response = client.get(
            "/api/v1/vendor/marketplace/settings",
            headers=auth_headers,
        )

        assert response.status_code == 403
