# tests/unit/models/test_merchant_domain.py
"""Unit tests for MerchantDomain model and related model properties."""

import uuid
from datetime import UTC, datetime

import pytest

from app.modules.tenancy.models.merchant_domain import MerchantDomain
from app.modules.tenancy.models.store_domain import StoreDomain

# =============================================================================
# MODEL TESTS
# =============================================================================


@pytest.mark.unit
@pytest.mark.tenancy
class TestMerchantDomainModel:
    """Test suite for MerchantDomain model."""

    def test_create_merchant_domain(self, db, test_merchant):
        """Test creating a MerchantDomain with required fields."""
        unique_id = str(uuid.uuid4())[:8]
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"test{unique_id}.example.com",
            is_primary=True,
            verification_token=f"token_{unique_id}",
        )
        db.add(domain)
        db.commit()
        db.refresh(domain)

        assert domain.id is not None
        assert domain.merchant_id == test_merchant.id
        assert domain.is_primary is True
        assert domain.is_active is True  # default
        assert domain.is_verified is False  # default
        assert domain.ssl_status == "pending"  # default
        assert domain.verified_at is None
        assert domain.platform_id is None

    def test_merchant_domain_defaults(self, db, test_merchant):
        """Test default values for MerchantDomain."""
        unique_id = str(uuid.uuid4())[:8]
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"defaults{unique_id}.example.com",
            verification_token=f"dtoken_{unique_id}",
        )
        db.add(domain)
        db.commit()
        db.refresh(domain)

        assert domain.is_primary is True
        assert domain.is_active is True
        assert domain.is_verified is False
        assert domain.ssl_status == "pending"

    def test_merchant_domain_repr(self, db, test_merchant):
        """Test string representation."""
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain="repr.example.com",
        )
        assert "repr.example.com" in repr(domain)
        assert str(test_merchant.id) in repr(domain)

    def test_merchant_domain_full_url(self):
        """Test full_url property."""
        domain = MerchantDomain(domain="test.example.com")
        assert domain.full_url == "https://test.example.com"

    def test_normalize_domain_removes_protocol(self):
        """Test normalize_domain strips protocols."""
        assert MerchantDomain.normalize_domain("https://example.com") == "example.com"
        assert MerchantDomain.normalize_domain("http://example.com") == "example.com"

    def test_normalize_domain_removes_trailing_slash(self):
        """Test normalize_domain strips trailing slashes."""
        assert MerchantDomain.normalize_domain("example.com/") == "example.com"

    def test_normalize_domain_lowercases(self):
        """Test normalize_domain converts to lowercase."""
        assert MerchantDomain.normalize_domain("EXAMPLE.COM") == "example.com"

    def test_unique_domain_constraint(self, db, test_merchant):
        """Test that domain must be unique across all merchant domains."""
        unique_id = str(uuid.uuid4())[:8]
        domain_name = f"unique{unique_id}.example.com"

        domain1 = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=domain_name,
            verification_token=f"t1_{unique_id}",
        )
        db.add(domain1)
        db.commit()

        domain2 = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=domain_name,
            verification_token=f"t2_{unique_id}",
        )
        db.add(domain2)
        with pytest.raises(Exception):  # IntegrityError
            db.commit()
        db.rollback()


# =============================================================================
# MERCHANT.primary_domain PROPERTY TESTS
# =============================================================================


@pytest.mark.unit
@pytest.mark.tenancy
class TestMerchantPrimaryDomain:
    """Test Merchant.primary_domain property."""

    def test_primary_domain_returns_active_verified_primary(self, db, test_merchant):
        """Test primary_domain returns domain when active, verified, and primary."""
        unique_id = str(uuid.uuid4())[:8]
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"primary{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"pt_{unique_id}",
        )
        db.add(domain)
        db.commit()
        db.refresh(test_merchant)

        assert test_merchant.primary_domain == f"primary{unique_id}.example.com"

    def test_primary_domain_returns_none_when_no_domains(self, db, test_merchant):
        """Test primary_domain returns None when merchant has no domains."""
        db.refresh(test_merchant)
        # Fresh merchant without any domains added in this test
        # Need to check if it may have domains from other fixtures
        # Just verify the property works without error
        result = test_merchant.primary_domain
        assert result is None or isinstance(result, str)

    def test_primary_domain_returns_none_when_inactive(self, db, test_merchant):
        """Test primary_domain returns None when domain is inactive."""
        unique_id = str(uuid.uuid4())[:8]
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"inactive{unique_id}.example.com",
            is_primary=True,
            is_active=False,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"it_{unique_id}",
        )
        db.add(domain)
        db.commit()
        db.refresh(test_merchant)

        assert test_merchant.primary_domain is None

    def test_primary_domain_returns_none_when_unverified(self, db, test_merchant):
        """Test primary_domain returns None when domain is unverified."""
        unique_id = str(uuid.uuid4())[:8]
        domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"unverified{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=False,
            verification_token=f"ut_{unique_id}",
        )
        db.add(domain)
        db.commit()
        db.refresh(test_merchant)

        assert test_merchant.primary_domain is None


# =============================================================================
# STORE.effective_domain PROPERTY TESTS
# =============================================================================


@pytest.mark.unit
@pytest.mark.tenancy
class TestStoreEffectiveDomain:
    """Test Store.effective_domain inheritance chain."""

    def test_effective_domain_returns_store_domain_when_present(self, db, test_store):
        """Test effective_domain returns store's own custom domain (highest priority)."""
        unique_id = str(uuid.uuid4())[:8]
        store_domain = StoreDomain(
            store_id=test_store.id,
            domain=f"storeover{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"sd_{unique_id}",
        )
        db.add(store_domain)
        db.commit()
        db.refresh(test_store)

        assert test_store.effective_domain == f"storeover{unique_id}.example.com"

    def test_effective_domain_returns_merchant_domain_when_no_store_domain(
        self, db, test_store, test_merchant
    ):
        """Test effective_domain returns merchant domain when no store domain."""
        unique_id = str(uuid.uuid4())[:8]
        merchant_domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"merchant{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"md_{unique_id}",
        )
        db.add(merchant_domain)
        db.commit()
        db.refresh(test_store)
        db.refresh(test_merchant)

        assert test_store.effective_domain == f"merchant{unique_id}.example.com"

    def test_effective_domain_returns_subdomain_fallback(self, db, test_store):
        """Test effective_domain returns subdomain fallback when no custom domains."""
        db.refresh(test_store)
        # With no store or merchant domains, should fall back to subdomain
        result = test_store.effective_domain
        assert test_store.subdomain in result

    def test_effective_domain_store_domain_overrides_merchant_domain(
        self, db, test_store, test_merchant
    ):
        """Test that store domain takes priority over merchant domain."""
        unique_id = str(uuid.uuid4())[:8]

        # Add merchant domain
        merchant_domain = MerchantDomain(
            merchant_id=test_merchant.id,
            domain=f"merchantpri{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"mpri_{unique_id}",
        )
        db.add(merchant_domain)

        # Add store domain (should take priority)
        store_domain = StoreDomain(
            store_id=test_store.id,
            domain=f"storepri{unique_id}.example.com",
            is_primary=True,
            is_active=True,
            is_verified=True,
            verified_at=datetime.now(UTC),
            verification_token=f"spri_{unique_id}",
        )
        db.add(store_domain)
        db.commit()
        db.refresh(test_store)
        db.refresh(test_merchant)

        assert test_store.effective_domain == f"storepri{unique_id}.example.com"
