"""Tests for parse_address_components operator."""

import os
import sys

import pytest

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

from fmatch.saas.operators.parse_address_components import parse_address_components


class TestParseAddressComponents:
    """Comprehensive tests for parse_address_components operator."""

    @pytest.mark.parametrize(
        "address,expected",
        [
            (
                "123 Main St, San Francisco, CA 94105",
                ["123 Main St", "San Francisco", "CA", "94105"],
            ),
            (
                "1600 Amphitheatre Pkwy, Mountain View, CA 94043",
                ["1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043"],
            ),
            (
                "350 Fifth Avenue, New York, NY 10118",
                ["350 Fifth Avenue", "New York", "NY", "10118"],
            ),
        ],
    )
    def test_standard_us_addresses(self, address, expected):
        """Test parsing of standard US addresses."""
        result = parse_address_components(address)
        assert result["value"] == expected
        assert result["meta"]["confidence"] == pytest.approx(1.0)

    @pytest.mark.parametrize(
        "address,street,state",
        [
            ("10 Downing St, London SW1A 2AA, UK", "10 Downing St", "UK"),
            (
                "1 Avenue des Champs-Élysées, Paris 75008, France",
                "1 Avenue des Champs-Élysées",
                "France",
            ),
            (
                "Alexanderplatz 1, Berlin 10178, Germany",
                "Alexanderplatz 1",
                "Germany",
            ),
        ],
    )
    def test_international_addresses(self, address, street, state):
        """Test best-effort parsing of international addresses."""
        result = parse_address_components(address)
        values = result["value"]
        assert len(values) == 4
        assert values[0] == street
        assert values[2] == state
        # Best-effort parsing still returns strings
        assert all(isinstance(component, str) for component in values)

    @pytest.mark.parametrize(
        "address,expected",
        [
            ("", ["", "", "", ""]),
            ("   ", ["", "", "", ""]),
            ("Invalid", ["Invalid", "", "", ""]),
            ("Just a string", ["Just a string", "", "", ""]),
        ],
    )
    def test_edge_cases(self, address, expected):
        """Test handling of invalid/empty addresses."""
        result = parse_address_components(address)
        assert result["value"] == expected

    def test_none_input(self):
        """None input surfaces a null_input error via safe_transform."""
        result = parse_address_components(None)
        assert result["value"] is None
        assert result["error"] == "null_input"

    @pytest.mark.parametrize(
        "address",
        [
            "  123 Main St,  San Francisco,  CA  94105  ",
            "123 Main St,\tSan Francisco,\tCA\t94105",
            "123 Main St,\nSan Francisco,\nCA\n94105",
        ],
    )
    def test_whitespace_normalization(self, address):
        """Test that whitespace is normalized."""
        result = parse_address_components(address)
        assert result["value"] == ["123 Main St", "San Francisco", "CA", "94105"]

    def test_partial_addresses(self):
        """Test addresses with missing components."""
        result = parse_address_components("123 Main St, San Francisco, CA")
        assert result["value"] == ["123 Main St", "San Francisco", "CA", ""]

        result = parse_address_components("123 Main St, San Francisco")
        assert result["value"] == ["123 Main St", "San Francisco", "", ""]

    def test_two_part_city_state_postal_fallback(self):
        result = parse_address_components("123 Main St, Boston MA 02134")
        assert result["value"] == ["123 Main St", "Boston", "MA", "02134"]

    def test_city_postal_country_fallback(self):
        result = parse_address_components("123 Main St, London SW1A 2AA, UK")
        assert result["value"] == ["123 Main St", "London", "UK", "SW1A 2AA"]

    def test_apartment_numbers(self):
        """Test addresses with apartment/suite numbers."""
        result = parse_address_components("123 Main St Apt 4B, San Francisco, CA 94105")
        assert result["value"] == [
            "123 Main St Apt 4B",
            "San Francisco",
            "CA",
            "94105",
        ]

    def test_po_boxes(self):
        """Test P.O. Box addresses."""
        result = parse_address_components("PO Box 1234, San Francisco, CA 94105")
        assert result["value"] == ["PO Box 1234", "San Francisco", "CA", "94105"]

    @pytest.mark.parametrize(
        "address",
        [
            "123 O'Brien St, San José, CA 94105",
            "123 Main St #4, San Francisco, CA 94105",
            "123 Main St, Apt. 4-B, San Francisco, CA 94105",
        ],
    )
    def test_special_characters(self, address):
        """Test addresses with special characters."""
        result = parse_address_components(address)
        assert len(result["value"]) == 4
        assert all(isinstance(component, str) for component in result["value"])

    def test_output_structure(self):
        """Test that output structure is consistent."""
        result = parse_address_components("123 Main St, SF, CA 94105")
        assert isinstance(result, dict)
        assert "value" in result
        assert isinstance(result["value"], list)
        assert len(result["value"]) == 4
        for component in result["value"]:
            assert isinstance(component, str)

    def test_very_long_addresses(self):
        """Test handling of very long addresses."""
        long_address = "A" * 500 + ", " + "B" * 100 + ", CA 94105"
        result = parse_address_components(long_address)
        assert len(result["value"]) == 4
        assert result["value"][0].startswith("A" * 100)


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

    if exit_code == 0:
        print("\nAll parse_address_components tests passed!")
    else:
        print(f"\nTests failed with exit code: {exit_code}")

    return exit_code


if __name__ == "__main__":
    raise SystemExit(run_tests())
