"""
Unit tests for domain family registry and normalization
========================================================
"""
import pytest
from pathlib import Path
import tempfile
import yaml

from src.fmatch.saas.services.domain_family import (
    domain_normalize,
    DomainFamilyRegistry,
    DomainRelation
)


class TestDomainNormalize:
    """Test domain normalization function"""
    
    def test_email_normalization(self):
        """Test email address normalization"""
        assert domain_normalize("john.doe@google.com") == "google.com"
        assert domain_normalize("ADMIN@MICROSOFT.COM") == "microsoft.com"
        assert domain_normalize("user@sub.example.com") == "example.com"
    
    def test_url_normalization(self):
        """Test URL normalization"""
        assert domain_normalize("https://www.google.com/search") == "google.com"
        assert domain_normalize("http://docs.microsoft.com:8080/api") == "microsoft.com"
        assert domain_normalize("ftp://files.example.com/data") == "example.com"
    
    def test_domain_normalization(self):
        """Test plain domain normalization"""
        assert domain_normalize("google.com") == "google.com"
        assert domain_normalize("WWW.MICROSOFT.COM") == "microsoft.com"
        assert domain_normalize("subdomain.example.co.uk") == "example.co.uk"
    
    def test_idn_punycode(self):
        """Test IDN/punycode handling"""
        # Chinese domain
        assert domain_normalize("测试.中国") is not None  # Should convert to punycode
        # Emoji domain (if registered)
        assert domain_normalize("👨‍💻.ws") is not None  # Should handle or return None
    
    def test_b2c_filtering(self):
        """Test that B2C/personal domains return None"""
        assert domain_normalize("user@gmail.com") is None
        assert domain_normalize("admin@yahoo.com") is None
        assert domain_normalize("test@outlook.com") is None
        assert domain_normalize("https://www.hotmail.com") is None
    
    def test_invalid_inputs(self):
        """Test invalid inputs return None"""
        assert domain_normalize(None) is None
        assert domain_normalize("") is None
        assert domain_normalize("not-a-domain") is None
        assert domain_normalize("192.168.1.1") is None  # IP address
        assert domain_normalize("localhost") is None


class TestDomainFamilyRegistry:
    """Test domain family registry"""
    
    @pytest.fixture
    def temp_seed_file(self):
        """Create a temporary seed file for testing"""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
            yaml.dump({
                'families': [
                    {
                        'family_id': 'test_corp',
                        'parent': 'testcorp.com',
                        'aliases': ['sub1.testcorp.com', 'brand.com']
                    },
                    {
                        'family_id': 'alphabet',
                        'parent': 'google.com',
                        'aliases': ['youtube.com', 'android.com']
                    }
                ]
            }, f)
            temp_path = f.name
        
        yield temp_path
        
        # Cleanup
        Path(temp_path).unlink(missing_ok=True)
    
    def test_registry_initialization(self, temp_seed_file):
        """Test registry initializes from seed file"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Check families loaded
        assert 'test_corp' in registry.family_to_domains
        assert 'alphabet' in registry.family_to_domains
        
        # Check domains mapped
        assert registry.get_domain_family('testcorp.com') == 'test_corp'
        assert registry.get_domain_family('youtube.com') == 'alphabet'
    
    def test_exact_relation(self, temp_seed_file):
        """Test EXACT domain relations"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Same domain
        rel, fam = registry.relation('google.com', 'google.com')
        assert rel == DomainRelation.EXACT
        assert fam == 'alphabet'
        
        # Same domain with different formats
        rel, fam = registry.relation('user@google.com', 'https://www.google.com')
        assert rel == DomainRelation.EXACT
        assert fam == 'alphabet'
    
    def test_family_relation(self, temp_seed_file):
        """Test FAMILY domain relations"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Same family
        rel, fam = registry.relation('google.com', 'youtube.com')
        assert rel == DomainRelation.FAMILY
        assert fam == 'alphabet'
        
        # Same family with emails
        rel, fam = registry.relation('john@google.com', 'admin@youtube.com')
        assert rel == DomainRelation.FAMILY
        assert fam == 'alphabet'
    
    def test_subdomain_normalization(self, temp_seed_file):
        """Test that subdomains are normalized to registrable domain"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Subdomains get normalized to registrable domain, so they become EXACT
        # app.example.com -> example.com, example.com -> example.com
        rel, fam = registry.relation('app.example.com', 'example.com')
        assert rel == DomainRelation.EXACT  # Both normalize to example.com
        
        rel, fam = registry.relation('example.com', 'www.example.com')
        assert rel == DomainRelation.EXACT  # Both normalize to example.com
    
    def test_none_relation(self, temp_seed_file):
        """Test NONE relations (no relationship)"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Different domains
        rel, fam = registry.relation('google.com', 'microsoft.com')
        assert rel == DomainRelation.NONE
        assert fam is None
        
        # B2C domain (returns None)
        rel, fam = registry.relation('user@gmail.com', 'google.com')
        assert rel == DomainRelation.NONE
        assert fam is None
    
    def test_add_override(self, temp_seed_file):
        """Test adding domain overrides"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        # Add new domain to existing family
        registry.add_override('newbrand.com', 'test_corp', account_id='test123')
        
        # Check it was added
        assert registry.get_domain_family('newbrand.com') == 'test_corp'
        assert 'newbrand.com' in registry.get_family_domains('test_corp')
        
        # Check relation with family member
        rel, fam = registry.relation('newbrand.com', 'testcorp.com')
        assert rel == DomainRelation.FAMILY
        assert fam == 'test_corp'
    
    def test_reload_with_ttl(self, temp_seed_file):
        """Test registry reload with TTL"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file, ttl_s=1)
        
        # First reload should work
        assert registry.reload() is False  # Just loaded, shouldn't reload
        
        # Wait for TTL to expire
        import time
        time.sleep(1.1)
        
        # Should reload now
        assert registry.reload() is True
        
        # Force reload should always work
        assert registry.reload(force=True) is True
    
    def test_to_dict_export(self, temp_seed_file):
        """Test exporting registry as dict"""
        registry = DomainFamilyRegistry(seed_path=temp_seed_file)
        
        export = registry.to_dict()
        
        assert 'families' in export
        assert 'total_families' in export
        assert 'total_domains' in export
        assert export['total_families'] == 2
        
        # Check family structure
        test_corp = next(f for f in export['families'] if f['family_id'] == 'test_corp')
        assert test_corp['parent'] == 'testcorp.com'
        assert 'brand.com' in test_corp['aliases']


class TestIntegration:
    """Integration tests for domain family system"""
    
    def test_l2a_tier_classification(self):
        """Test that domain relations affect L2A tier classification"""
        # This would test the full integration with L2A service
        # For now, just test the building blocks work together
        
        # Normalize domains
        lead_domain = domain_normalize("john@google.com")
        acct_domain = domain_normalize("https://www.google.com/about")
        
        assert lead_domain == "google.com"
        assert acct_domain == "google.com"
        
        # Would be EXACT relation -> CERTAIN tier
        registry = DomainFamilyRegistry()
        rel, _ = registry.relation(lead_domain, acct_domain)
        assert rel == DomainRelation.EXACT
    
    def test_b2c_suppression(self):
        """Test B2C domains are properly suppressed"""
        # Personal email should normalize to None
        personal = domain_normalize("user@gmail.com")
        assert personal is None
        
        # Business email should normalize properly
        business = domain_normalize("user@google.com")
        assert business == "google.com"
        
        # Registry should handle None gracefully
        registry = DomainFamilyRegistry()
        rel, fam = registry.relation("user@gmail.com", "google.com")
        assert rel == DomainRelation.NONE
        assert fam is None


class TestSimpleDomainFamilyRegistry:
    """Simple unit tests for DomainFamilyRegistry as requested"""
    
    def test_exact(self):
        """Test exact domain match"""
        reg = DomainFamilyRegistry(seed_path="config/domain_families.yaml")
        rel, fam = reg.relation("google.com", "google.com")
        assert rel == DomainRelation.EXACT
    
    def test_family(self):
        """Test family domain match"""
        reg = DomainFamilyRegistry(seed_path="config/domain_families.yaml")
        # Assuming youtube.com and google.com are in the same family in the seed file
        rel, fam = reg.relation("youtube.com", "google.com")
        # If they're in the same family, should be FAMILY
        # If not in seed file, will be NONE
        assert rel in (DomainRelation.FAMILY, DomainRelation.NONE)
        if rel == DomainRelation.FAMILY:
            assert fam in {"alphabet", "google", "youtube"}  # depending on seed
    
    def test_b2c_is_none(self):
        """Test that B2C domains return NONE"""
        reg = DomainFamilyRegistry(seed_path="config/domain_families.yaml")
        rel, fam = reg.relation("gmail.com", "google.com")
        assert rel == DomainRelation.NONE  # gmail is B2C


if __name__ == "__main__":
    pytest.main([__file__, "-v"])