"""
Comprehensive tests for high-traffic normalization operators.

These operators are heavily used in B2B data pipelines:
- normalize_country
- normalize_state
- normalize_industry
- normalize_title
"""

import pytest
import sys
import os

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))

# Disable LLM fallbacks for deterministic testing
os.environ["TRANSFORM_ENABLE_LLM_FALLBACK"] = "false"

from fmatch.saas.operators.normalize_country import normalize_country
from fmatch.saas.operators.normalize_state import normalize_state
from fmatch.saas.operators.normalize_industry import normalize_industry
from fmatch.saas.operators.normalize_title import normalize_title


class TestNormalizeCountry:
    """Comprehensive tests for normalize_country operator."""

    @pytest.mark.parametrize("input_country,expected", [
        # US variations
        ("USA", "US"),
        ("us", "US"),
        ("United States", "US"),
        ("U.S.", "US"),
        ("U.S.A.", "US"),
        ("America", "US"),

        # UK variations
        ("United Kingdom", "GB"),
        ("UK", "GB"),
        ("GB", "GB"),
        ("Great Britain", "GB"),

        # Other major countries
        ("Canada", "CA"),
        ("ca", "CA"),
        ("Australia", "AU"),
        ("Germany", "DE"),
        ("France", "FR"),
        ("Spain", "ES"),
        ("Italy", "IT"),
        ("Netherlands", "NL"),
        ("India", "IN"),
        ("Brazil", "BR"),
        ("Mexico", "MX"),
        ("Japan", "JP"),
        ("UAE", "AE"),
        ("Czech Republic", "CZ"),
        ("South Korea", "KR"),
        ("Ivory Coast", "CI"),
        ("Macau", "MO"),
    ])
    def test_country_normalization(self, input_country, expected):
        """Test normalization of common country names and codes."""
        result = normalize_country(input_country)
        assert result["value"] == expected

    @pytest.mark.parametrize("input_country", [
        # Case variations
        "usa",
        "USA",
        "UsA",
        "uSa",
    ])
    def test_case_insensitivity(self, input_country):
        """Test that country matching is case-insensitive."""
        result = normalize_country(input_country)
        assert result["value"] == "US"

    @pytest.mark.parametrize("input_country", [
        "",
        "   ",
        None,
        "Unknown Country",
        "XYZ",
    ])
    def test_unknown_countries(self, input_country):
        """Test handling of unknown/invalid countries."""
        result = normalize_country(input_country)
        assert result["value"] == ""

    @pytest.mark.parametrize("input_country", [
        "  USA  ",
        "\tUnited States\t",
        "\nCanada\n",
    ])
    def test_whitespace_handling(self, input_country):
        """Test that whitespace is trimmed."""
        result = normalize_country(input_country)
        assert result["value"] in ["US", "CA"]


class TestNormalizeState:
    """Comprehensive tests for normalize_state operator."""

    @pytest.mark.parametrize("input_state,expected", [
        # US states - codes -> full names
        ("CA", "California"),
        ("NY", "New York"),
        ("TX", "Texas"),
        ("FL", "Florida"),
        ("IL", "Illinois"),

        # US states - full names -> full names (normalized)
        ("California", "California"),
        ("New York", "New York"),
        ("Texas", "Texas"),
        ("Florida", "Florida"),
        ("Illinois", "Illinois"),
    ])
    def test_us_state_normalization(self, input_state, expected):
        """Test US state normalization - returns full names."""
        result = normalize_state(input_state, country="US")
        assert result["value"] == expected

    @pytest.mark.parametrize("input_state,expected", [
        # Canadian provinces - codes -> full names
        ("ON", "Ontario"),
        ("QC", "Quebec"),
        ("BC", "British Columbia"),
        ("AB", "Alberta"),
        # Canadian provinces - full names -> full names (normalized)
        ("Ontario", "Ontario"),
        ("Quebec", "Quebec"),
        ("British Columbia", "British Columbia"),
        ("Alberta", "Alberta"),
    ])
    def test_canadian_province_normalization(self, input_state, expected):
        """Test Canadian province normalization - returns full names."""
        result = normalize_state(input_state, country="CA")
        assert result["value"] == expected

    @pytest.mark.parametrize("input_state,expected", [
        # Australian states - codes -> full names
        ("NSW", "New South Wales"),
        ("VIC", "Victoria"),
        ("QLD", "Queensland"),
        # Australian states - full names -> full names (normalized)
        ("New South Wales", "New South Wales"),
        ("Victoria", "Victoria"),
        ("Queensland", "Queensland"),
    ])
    def test_australian_state_normalization(self, input_state, expected):
        """Test Australian state normalization - returns full names."""
        result = normalize_state(input_state, country="AU")
        assert result["value"] == expected

    @pytest.mark.parametrize("input_state", [
        "",
        "   ",
        None,
        "Invalid State",
    ])
    def test_invalid_states(self, input_state):
        """Test handling of invalid states."""
        result = normalize_state(input_state)
        assert result["value"] == ""

    def test_default_country_us(self):
        """Test that default country is US when not specified."""
        result = normalize_state("California")
        assert result["value"] == "California"

    def test_explicit_country_blocks_us_fallback(self):
        """Explicit non-US country context should not silently map US states."""
        assert normalize_state("California", country="CA")["value"] == ""
        assert normalize_state("CA", country="CA")["value"] == ""
        assert normalize_state("Ontario", country="US")["value"] == ""

    @pytest.mark.parametrize("input_state", [
        "california",
        "CALIFORNIA",
        "CaLiFoRnIa",
    ])
    def test_case_insensitivity(self, input_state):
        """Test case-insensitive matching - returns properly cased full name."""
        result = normalize_state(input_state)
        assert result["value"] == "California"


class TestNormalizeIndustry:
    """Comprehensive tests for normalize_industry operator."""

    @pytest.mark.parametrize("input_industry,expected", [
        # Software & Technology
        ("SaaS", "Software"),
        ("Software as a Service", "Software"),
        ("B2B Software", "Software"),
        ("Enterprise Software", "Software"),
        ("Tech", "Technology"),
        ("IT", "Technology"),
        ("Information Technology", "Technology"),
        ("Cloud", "Cloud Computing"),
        ("Cloud Services", "Cloud Computing"),
        ("IaaS", "Cloud Computing"),
        ("Cybersecurity", "Cybersecurity"),
        ("AI", "Artificial Intelligence"),
        ("Machine Learning", "Artificial Intelligence"),
        ("ML", "Artificial Intelligence"),

        # Financial Services
        ("FinTech", "Financial Services"),
        ("Financial Technology", "Financial Services"),
        ("Finance", "Financial Services"),
        ("Banking", "Financial Services"),
        ("InsurTech", "Insurance"),
        ("Payments", "Payments"),

        # Healthcare
        ("HealthTech", "Healthcare"),
        ("Health Care", "Healthcare"),
        ("Digital Health", "Healthcare"),
        ("Biotech", "Biotechnology"),
        ("Life Sciences", "Biotechnology"),
        ("Pharma", "Pharmaceuticals"),

        # E-commerce & Retail
        ("E-Commerce", "E-Commerce"),
        ("Ecommerce", "E-Commerce"),
        ("Online Retail", "E-Commerce"),
        ("Retail Tech", "Retail"),

        # Marketing & Advertising
        ("MarTech", "Marketing Technology"),
        ("Marketing Automation", "Marketing Technology"),
        ("AdTech", "Advertising"),
        ("Ad Tech", "Advertising"),

        # Other
        ("Telecom", "Telecommunications"),
        ("Manufacturing", "Manufacturing"),
        ("Consulting", "Consulting"),
        ("EdTech", "Education"),
        ("PropTech", "Real Estate"),
        ("HR Tech", "Human Resources"),
    ])
    def test_industry_normalization(self, input_industry, expected):
        """Test normalization of common B2B industries."""
        result = normalize_industry(input_industry)
        assert result["value"] == expected
        assert result["confidence"] >= 0.5

    @pytest.mark.parametrize("input_industry", [
        "saas",
        "SAAS",
        "SaaS",
        "Saas",
    ])
    def test_case_insensitivity(self, input_industry):
        """Test case-insensitive matching."""
        result = normalize_industry(input_industry)
        assert result["value"] == "Software"

    @pytest.mark.parametrize("input_industry,expected", [
        ("", None),
        ("   ", None),
        (None, None),
    ])
    def test_empty_industry(self, input_industry, expected):
        """Test handling of empty inputs."""
        result = normalize_industry(input_industry)
        assert result["value"] == expected
        assert result["confidence"] == 0.0

    def test_unknown_industry_returns_original(self):
        """Test that unknown industries return original value."""
        result = normalize_industry("Mysterious Industry XYZ")
        assert result["value"] == "Mysterious Industry XYZ"
        assert result["confidence"] == 0
        assert result["normalized"] is False

    def test_compound_industry_detection(self):
        """Test detection of compound industries."""
        result = normalize_industry("Software and Consulting")
        # Should detect multiple industries
        assert "confidence" in result
        # Value could be either single or compound
        assert result["value"]

    @pytest.mark.parametrize("input_industry", [
        "Financial Services & Technology",
        "FinTech Solutions",
        "Healthcare Technology",
    ])
    def test_fuzzy_matching(self, input_industry):
        """Test fuzzy matching for partial industry names."""
        result = normalize_industry(input_industry)
        # Should find a match with some confidence
        assert result["value"]
        assert result["confidence"] > 0


class TestNormalizeTitle:
    """Comprehensive tests for normalize_title operator."""

    @pytest.mark.parametrize("input_title,expected_title", [
        # Executive titles
        ("CEO", "CEO"),
        ("Chief Executive Officer", "Chief Executive Officer"),
        ("CTO", "CTO"),
        ("Chief Technology Officer", "Chief Technology Officer"),
        ("CFO", "CFO"),
        ("COO", "COO"),
        ("CMO", "CMO"),

        # VP titles
        ("VP Sales", "VP Sales"),
        ("Vice President of Marketing", "Vice President Of Marketing"),
        ("SVP Engineering", "SVP Engineering"),
        ("EVP Operations", "EVP Operations"),

        # Director titles
        ("Director of Engineering", "Director Of Engineering"),
        ("Engineering Director", "Engineering Director"),
        ("Director, Product Management", "Director Product Management"),

        # Manager titles
        ("Engineering Manager", "Engineering Manager"),
        ("Product Manager", "Product Manager"),
        ("Sales Manager", "Sales Manager"),

        # IC titles
        ("Software Engineer", "Software Engineer"),
        ("Senior Software Engineer", "Senior Software Engineer"),
        ("Staff Engineer", "Staff Engineer"),
        ("Principal Engineer", "Principal Engineer"),
    ])
    def test_title_normalization(self, input_title, expected_title):
        """Test normalization of common job titles."""
        result = normalize_title(input_title)
        assert result["value"]["title"] == expected_title

    @pytest.mark.parametrize("input_title,expected_seniority", [
        ("CEO", "CXO"),
        ("CTO", "CXO"),
        ("VP Sales", "VP"),
        ("SVP Marketing", "VP"),
        ("Director of Engineering", "Director"),
        ("Engineering Manager", "Manager"),
        ("Senior Software Engineer", "IC"),
        ("Software Engineer", "IC"),
    ])
    def test_seniority_detection(self, input_title, expected_seniority):
        """Test detection of seniority levels."""
        result = normalize_title(input_title)
        assert result["value"]["seniority"] == expected_seniority

    @pytest.mark.parametrize("input_title,expected_dept", [
        ("VP of Sales", "Sales"),
        ("Engineering Manager", "Engineering"),
        ("Marketing Director", "Marketing"),
        ("Product Manager", "Product"),
        ("Customer Success Manager", "Customer Success"),
        ("Head of Finance", "Finance"),
        ("HR Director", "HR"),
    ])
    def test_department_detection(self, input_title, expected_dept):
        """Test detection of departments."""
        result = normalize_title(input_title)
        assert result["value"]["department"] == expected_dept

    @pytest.mark.parametrize("input_title,expected_clean", [
        ("VP / Sales", "VP Sales"),
        ("Director - Engineering", "Director Engineering"),
        ("Manager (Product)", "Manager Product"),
        ("VP   of    Sales", "VP Of Sales"),
    ])
    def test_special_character_cleaning(self, input_title, expected_clean):
        """Test cleaning of special characters."""
        result = normalize_title(input_title)
        # Should clean slashes, dashes, parens, excess spaces
        assert "/" not in result["value"]["title"]
        assert "  " not in result["value"]["title"]

    @pytest.mark.parametrize("input_title", [
        "",
        "   ",
        None,
    ])
    def test_empty_titles(self, input_title):
        """Test handling of empty titles."""
        result = normalize_title(input_title)
        assert result["value"]["title"] == ""
        assert result["value"]["seniority"] == "IC"  # Default

    def test_title_case_preservation(self):
        """Test that acronyms are preserved in uppercase."""
        result = normalize_title("vp of sales")
        assert "VP" in result["value"]["title"]
        assert result["value"]["title"] == "VP Of Sales"

    @pytest.mark.parametrize("input_title", [
        "ceo",
        "CEO",
        "Ceo",
    ])
    def test_acronym_uppercase(self, input_title):
        """Test that executive acronyms are uppercased."""
        result = normalize_title(input_title)
        assert result["value"]["title"] == "CEO"


def run_tests():
    """Run all tests and report results."""
    exit_code = pytest.main([__file__, "-v", "--tb=short"])

    if exit_code == 0:
        print("\n✅ All normalization operator tests passed!")
    else:
        print(f"\n❌ Tests failed with exit code: {exit_code}")

    return exit_code


if __name__ == "__main__":
    exit(run_tests())
