# tests/unit/middleware/test_fail_closed_store_context.py
"""
Unit tests for fail-closed store context resolution.

Verifies that subdomain detection with a platform context:
1. Tries StorePlatform.custom_subdomain first (platform-specific override)
2. Falls back to Store.subdomain but ONLY if the store has an active
   membership on the detected platform (prevents cross-tenant leaks)
3. Returns None if the store has no membership on the platform
"""

from unittest.mock import MagicMock, Mock

import pytest
from sqlalchemy.orm import Session

from middleware.store_context import StoreContextManager


@pytest.mark.unit
@pytest.mark.middleware
class TestFailClosedStoreContext:
    """Ensure subdomain+platform blocks cross-tenant resolution."""

    def test_subdomain_not_found_at_all_returns_none(self):
        """
        Platform + subdomain + no custom_subdomain match + no Store.subdomain match → None.
        """
        mock_db = Mock(spec=Session)
        mock_platform = Mock()
        mock_platform.id = 2
        mock_platform.code = "loyalty"

        # All queries return None
        mock_db.query.return_value.filter.return_value.first.return_value = None
        mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = None

        context = {
            "detection_method": "subdomain",
            "subdomain": "nonexistent",
            "_platform": mock_platform,
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is None

    def test_subdomain_found_with_platform_membership_returns_store(self):
        """
        Platform + subdomain + Store.subdomain found + store HAS membership
        on this platform → return store.
        e.g. wizatech.omsflow.lu where WIZATECH is on OMS platform.
        """
        mock_db = Mock(spec=Session)
        mock_platform = Mock()
        mock_platform.id = 1
        mock_platform.code = "oms"

        mock_store = Mock()
        mock_store.id = 10
        mock_store.is_active = True
        mock_store.name = "WizaTech"

        mock_membership = Mock()  # Active StorePlatform entry

        call_count = [0]

        def side_effect_query(model):
            result = MagicMock()
            call_count[0] += 1
            if call_count[0] == 1:
                # StorePlatform.custom_subdomain lookup → no match
                result.filter.return_value.first.return_value = None
            elif call_count[0] == 2:
                # Store.subdomain lookup → found
                result.filter.return_value.filter.return_value.first.return_value = mock_store
            else:
                # StorePlatform membership check → exists
                result.filter.return_value.first.return_value = mock_membership
            return result

        mock_db.query.side_effect = side_effect_query

        context = {
            "detection_method": "subdomain",
            "subdomain": "wizatech",
            "_platform": mock_platform,
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is mock_store

    def test_subdomain_found_without_platform_membership_returns_none(self):
        """
        Platform + subdomain + Store.subdomain found but store has NO
        membership on this platform → None (cross-tenant blocked).
        e.g. loyalty-only-store.omsflow.lu where the store is only on loyalty.
        """
        mock_db = Mock(spec=Session)
        mock_platform = Mock()
        mock_platform.id = 1
        mock_platform.code = "oms"

        mock_store = Mock()
        mock_store.id = 10
        mock_store.is_active = True
        mock_store.name = "LoyaltyOnlyStore"

        call_count = [0]

        def side_effect_query(model):
            result = MagicMock()
            call_count[0] += 1
            if call_count[0] == 1:
                # StorePlatform.custom_subdomain lookup → no match
                result.filter.return_value.first.return_value = None
            elif call_count[0] == 2:
                # Store.subdomain lookup → found
                result.filter.return_value.filter.return_value.first.return_value = mock_store
            else:
                # StorePlatform membership check → NOT found (no membership)
                result.filter.return_value.first.return_value = None
            return result

        mock_db.query.side_effect = side_effect_query

        context = {
            "detection_method": "subdomain",
            "subdomain": "loyalty-only",
            "_platform": mock_platform,
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is None

    def test_custom_subdomain_found_returns_store(self):
        """Platform + subdomain + custom_subdomain found → correct store."""
        mock_db = Mock(spec=Session)
        mock_platform = Mock()
        mock_platform.id = 2
        mock_platform.code = "loyalty"

        mock_store_platform = Mock()
        mock_store_platform.store_id = 42

        mock_store = Mock()
        mock_store.id = 42
        mock_store.is_active = True
        mock_store.name = "Acme Rewards"

        call_count = [0]

        def side_effect_query(model):
            result = MagicMock()
            call_count[0] += 1
            if call_count[0] == 1:
                result.filter.return_value.first.return_value = mock_store_platform
            else:
                result.filter.return_value.first.return_value = mock_store
            return result

        mock_db.query.side_effect = side_effect_query

        context = {
            "detection_method": "subdomain",
            "subdomain": "acme-rewards",
            "_platform": mock_platform,
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is mock_store

    def test_no_platform_subdomain_uses_global_store(self):
        """No platform + subdomain → uses Store.subdomain (dev mode)."""
        mock_db = Mock(spec=Session)
        mock_store = Mock()
        mock_store.is_active = True
        mock_store.name = "Acme"

        mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_store

        context = {
            "detection_method": "subdomain",
            "subdomain": "acme",
            # No "_platform" key — dev mode
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is mock_store

    def test_path_based_uses_global_store(self):
        """Path-based detection always uses Store.subdomain (unchanged)."""
        mock_db = Mock(spec=Session)
        mock_platform = Mock()
        mock_platform.id = 1

        mock_store = Mock()
        mock_store.is_active = True
        mock_store.name = "Acme"

        mock_db.query.return_value.filter.return_value.filter.return_value.first.return_value = mock_store

        context = {
            "detection_method": "path",
            "subdomain": "ACME",
            "_platform": mock_platform,
        }

        store = StoreContextManager.get_store_from_context(mock_db, context)

        assert store is mock_store
