# tests/unit/middleware/test_merchant_domain_resolution.py
"""
Unit tests for merchant domain resolution in platform and store context middleware.

Tests cover:
- PlatformContextManager.get_platform_from_context() with merchant domain
- StoreContextManager.get_store_from_context() with merchant domain
- Priority: StoreDomain > MerchantDomain
- Fallthrough when MerchantDomain not found or inactive/unverified
"""

import uuid
from datetime import UTC, datetime

import pytest

from app.modules.tenancy.models import Store, StoreDomain
from app.modules.tenancy.models.merchant_domain import MerchantDomain
from middleware.platform_context import PlatformContextManager
from middleware.store_context import StoreContextManager

# =============================================================================
# PLATFORM CONTEXT - MERCHANT DOMAIN RESOLUTION
# =============================================================================


@pytest.mark.unit
@pytest.mark.middleware
class TestPlatformContextMerchantDomain:
    """Test PlatformContextManager.get_platform_from_context() with merchant domains."""

    def test_resolves_platform_from_merchant_domain(self, db, test_merchant, test_platform):
        """Test that platform is resolved from MerchantDomain.platform_id."""
        unique_id = str(uuid.uuid4())[:8]
        md = MerchantDomain(
            merchant_id=test_merchant.id,
            platform_id=test_platform.id,
            domain=f"mplatform{unique_id}.lu",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"mpt_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"mplatform{unique_id}.lu",
            "detection_method": "domain",
            "host": f"mplatform{unique_id}.lu",
            "original_path": "/",
        }

        platform = PlatformContextManager.get_platform_from_context(db, context)
        assert platform is not None
        assert platform.id == test_platform.id

    def test_falls_through_when_merchant_domain_not_found(self, db):
        """Test that None is returned when no MerchantDomain matches."""
        context = {
            "domain": "nonexistent.lu",
            "detection_method": "domain",
            "host": "nonexistent.lu",
            "original_path": "/",
        }

        platform = PlatformContextManager.get_platform_from_context(db, context)
        assert platform is None

    def test_falls_through_when_merchant_domain_inactive(self, db, test_merchant, test_platform):
        """Test that inactive MerchantDomain is skipped."""
        unique_id = str(uuid.uuid4())[:8]
        md = MerchantDomain(
            merchant_id=test_merchant.id,
            platform_id=test_platform.id,
            domain=f"inactive{unique_id}.lu",
            is_primary=True,
            is_active=False,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"ipt_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"inactive{unique_id}.lu",
            "detection_method": "domain",
            "host": f"inactive{unique_id}.lu",
            "original_path": "/",
        }

        platform = PlatformContextManager.get_platform_from_context(db, context)
        assert platform is None

    def test_falls_through_when_merchant_domain_unverified(self, db, test_merchant, test_platform):
        """Test that unverified MerchantDomain is skipped."""
        unique_id = str(uuid.uuid4())[:8]
        md = MerchantDomain(
            merchant_id=test_merchant.id,
            platform_id=test_platform.id,
            domain=f"unverified{unique_id}.lu",
            is_primary=True,
            is_active=True,
            is_verified=False,
            verification_token=f"upt_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"unverified{unique_id}.lu",
            "detection_method": "domain",
            "host": f"unverified{unique_id}.lu",
            "original_path": "/",
        }

        platform = PlatformContextManager.get_platform_from_context(db, context)
        assert platform is None

    def test_store_domain_takes_priority_over_merchant_domain(
        self, db, test_store, test_merchant, test_platform
    ):
        """Test that StoreDomain is checked before MerchantDomain."""
        unique_id = str(uuid.uuid4())[:8]
        domain_name = f"priority{unique_id}.lu"

        # Create a StoreDomain with this domain
        sd = StoreDomain(
            store_id=test_store.id,
            platform_id=test_platform.id,
            domain=domain_name,
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"sdp_{unique_id}",
        )
        db.add(sd)
        db.commit()

        context = {
            "domain": domain_name,
            "detection_method": "domain",
            "host": domain_name,
            "original_path": "/",
        }

        platform = PlatformContextManager.get_platform_from_context(db, context)
        assert platform is not None
        assert platform.id == test_platform.id


# =============================================================================
# STORE CONTEXT - MERCHANT DOMAIN RESOLUTION
# =============================================================================


@pytest.mark.unit
@pytest.mark.middleware
class TestStoreContextMerchantDomain:
    """Test StoreContextManager.get_store_from_context() with merchant domains."""

    def test_resolves_to_merchants_first_active_store(
        self, db, test_merchant, test_store
    ):
        """Test that merchant domain resolves to merchant's first active store."""
        unique_id = str(uuid.uuid4())[:8]
        md = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"mstore{unique_id}.lu",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"mst_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"mstore{unique_id}.lu",
            "detection_method": "custom_domain",
            "host": f"mstore{unique_id}.lu",
            "original_host": f"mstore{unique_id}.lu",
        }

        store = StoreContextManager.get_store_from_context(db, context)
        assert store is not None
        assert store.merchant_id == test_merchant.id
        assert context.get("merchant_domain") is True
        assert context.get("merchant_id") == test_merchant.id

    def test_store_domain_takes_priority_over_merchant_domain(
        self, db, test_store, test_merchant
    ):
        """Test that StoreDomain takes priority over MerchantDomain."""
        unique_id = str(uuid.uuid4())[:8]
        domain_name = f"storepri{unique_id}.lu"

        # Create StoreDomain for this store
        sd = StoreDomain(
            store_id=test_store.id,
            domain=domain_name,
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"sdpri_{unique_id}",
        )
        db.add(sd)
        db.commit()

        context = {
            "domain": domain_name,
            "detection_method": "custom_domain",
            "host": domain_name,
            "original_host": domain_name,
        }

        store = StoreContextManager.get_store_from_context(db, context)
        assert store is not None
        assert store.id == test_store.id
        # merchant_domain should NOT be set because StoreDomain resolved first
        assert context.get("merchant_domain") is None

    def test_falls_through_when_no_active_stores(self, db, other_merchant):
        """Test that None is returned when merchant has no active stores."""
        unique_id = str(uuid.uuid4())[:8]

        # Create inactive store for the merchant
        inactive = Store(
            merchant_id=other_merchant.id,
            store_code=f"INACTIVE_{unique_id.upper()}",
            subdomain=f"inactive{unique_id.lower()}",
            name="Inactive Store",
            is_active=False,
        )
        db.add(inactive)

        md = MerchantDomain(
            merchant_id=other_merchant.id,
            domain=f"noactive{unique_id}.lu",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"nat_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"noactive{unique_id}.lu",
            "detection_method": "custom_domain",
            "host": f"noactive{unique_id}.lu",
            "original_host": f"noactive{unique_id}.lu",
        }

        store = StoreContextManager.get_store_from_context(db, context)
        assert store is None

    def test_falls_through_when_merchant_domain_inactive(self, db, test_merchant):
        """Test that inactive MerchantDomain is not resolved to a store."""
        unique_id = str(uuid.uuid4())[:8]
        md = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"inactivem{unique_id}.lu",
            is_primary=True,
            is_active=False,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"im_{unique_id}",
        )
        db.add(md)
        db.commit()

        context = {
            "domain": f"inactivem{unique_id}.lu",
            "detection_method": "custom_domain",
            "host": f"inactivem{unique_id}.lu",
            "original_host": f"inactivem{unique_id}.lu",
        }

        store = StoreContextManager.get_store_from_context(db, context)
        assert store is None
