"""Perl parity tests for CLI interface."""

from click.testing import CliRunner
from panchanga_cli.cli import cli, get_place_coordinates


class TestCLIPerlParity:
    def test_place_coordinates_match_perl(self):
        """Test that place coordinates match Perl implementation exactly."""
        # Test major Vedic cities
        test_places = [
            ("ujjain", 23.2, 75.8, "Ujjain"),
            ("delhi", 28.6, 77.2, "Delhi"),
            ("mumbai", 19.0, 72.8, "Mumbai"),
            ("bangalore", 12.9, 77.6, "Bangalore"),
            ("chennai", 13.1, 80.2, "Chennai"),
            ("kolkata", 22.6, 88.4, "Kolkata"),
            ("hyderabad", 17.4, 78.5, "Hyderabad"),
            ("pune", 18.5, 73.9, "Pune"),
            ("ahmedabad", 23.0, 72.6, "Ahmedabad"),
            ("jaipur", 26.9, 75.8, "Jaipur"),
        ]

        for place_name, expected_lat, expected_lon, expected_name in test_places:
            coords = get_place_coordinates(place_name)
            assert coords is not None, f"Place {place_name} not found"
            lat, lon, name = coords
            assert lat == expected_lat, (
                f"Latitude mismatch for {place_name}: expected {expected_lat}, got {lat}"
            )
            assert lon == expected_lon, (
                f"Longitude mismatch for {place_name}: expected {expected_lon}, got {lon}"
            )
            assert name == expected_name, (
                f"Name mismatch for {place_name}: expected {expected_name}, got {name}"
            )

    def test_religious_places_match_perl(self):
        """Test that religious places match Perl implementation exactly."""
        test_places = [
            ("varanasi", 25.3, 83.0, "Varanasi"),
            ("haridwar", 29.9, 78.1, "Haridwar"),
            ("rishikesh", 30.1, 78.3, "Rishikesh"),
            ("mathura", 27.5, 77.7, "Mathura"),
            ("vrindavan", 27.6, 77.7, "Vrindavan"),
            ("ayodhya", 26.8, 82.2, "Ayodhya"),
            ("tirupati", 13.6, 79.4, "Tirupati"),
            ("madurai", 9.9, 78.1, "Madurai"),
            ("kanchipuram", 12.8, 79.7, "Kanchipuram"),
            ("thanjavur", 10.8, 79.1, "Thanjavur"),
        ]

        for place_name, expected_lat, expected_lon, expected_name in test_places:
            coords = get_place_coordinates(place_name)
            assert coords is not None, f"Place {place_name} not found"
            lat, lon, name = coords
            assert lat == expected_lat, (
                f"Latitude mismatch for {place_name}: expected {expected_lat}, got {lat}"
            )
            assert lon == expected_lon, (
                f"Longitude mismatch for {place_name}: expected {expected_lon}, got {lon}"
            )
            assert name == expected_name, (
                f"Name mismatch for {place_name}: expected {expected_name}, got {name}"
            )

    def test_international_cities_match_perl(self):
        """Test that international cities match Perl implementation exactly."""
        test_places = [
            ("kathmandu", 27.7, 85.3, "Kathmandu"),
            ("colombo", 6.9, 79.9, "Colombo"),
            ("dhaka", 23.8, 90.4, "Dhaka"),
            ("karachi", 24.9, 67.0, "Karachi"),
            ("lahore", 31.5, 74.4, "Lahore"),
            ("islamabad", 33.7, 73.1, "Islamabad"),
            ("singapore", 1.3, 103.8, "Singapore"),
            ("kuala_lumpur", 3.1, 101.7, "Kuala Lumpur"),
            ("bangkok", 13.8, 100.5, "Bangkok"),
            ("yangon", 16.9, 96.2, "Yangon"),
        ]

        for place_name, expected_lat, expected_lon, expected_name in test_places:
            coords = get_place_coordinates(place_name)
            assert coords is not None, f"Place {place_name} not found"
            lat, lon, name = coords
            assert lat == expected_lat, (
                f"Latitude mismatch for {place_name}: expected {expected_lat}, got {lat}"
            )
            assert lon == expected_lon, (
                f"Longitude mismatch for {place_name}: expected {expected_lon}, got {lon}"
            )
            assert name == expected_name, (
                f"Name mismatch for {place_name}: expected {expected_name}, got {name}"
            )

    def test_alternative_names_match_perl(self):
        """Test that alternative names match Perl implementation exactly."""
        test_places = [
            ("bombay", 19.0, 72.8, "Mumbai"),
            ("calcutta", 22.6, 88.4, "Kolkata"),
            ("madras", 13.1, 80.2, "Chennai"),
            ("benares", 25.3, 83.0, "Varanasi"),
            ("kashi", 25.3, 83.0, "Varanasi"),
            ("puri", 19.8, 85.8, "Purushottam"),
            ("jagannath", 19.8, 85.8, "Purushottam"),
        ]

        for place_name, expected_lat, expected_lon, expected_name in test_places:
            coords = get_place_coordinates(place_name)
            assert coords is not None, f"Place {place_name} not found"
            lat, lon, name = coords
            assert lat == expected_lat, (
                f"Latitude mismatch for {place_name}: expected {expected_lat}, got {lat}"
            )
            assert lon == expected_lon, (
                f"Longitude mismatch for {place_name}: expected {expected_lon}, got {lon}"
            )
            assert name == expected_name, (
                f"Name mismatch for {place_name}: expected {expected_name}, got {name}"
            )

    def test_places_command_output_structure(self):
        """Test that places command output structure matches Perl."""
        runner = CliRunner()
        result = runner.invoke(cli, ["places"])

        assert result.exit_code == 0
        output = result.output

        # Check that all expected sections are present
        assert "Available places:" in output
        assert "Major Vedic Cities:" in output
        assert "Religious and Historical Places:" in output
        assert "International Cities:" in output
        assert "Alternative Names:" in output
        assert "Note: Use --place 'place_name'" in output

        # Check that specific places are listed
        assert "ujjain" in output
        assert "delhi" in output
        assert "mumbai" in output
        assert "varanasi" in output
        assert "kathmandu" in output
        assert "bombay" in output

    def test_help_command_structure(self):
        """Test that help command structure matches Perl."""
        runner = CliRunner()
        result = runner.invoke(cli, ["--help"])

        assert result.exit_code == 0
        output = result.output

        # Check that all expected sections are present
        assert "Panchanga - Traditional Vedic Calendar" in output
        assert "Usage:" in output  # Click uses "Usage:" instead of "USAGE:"
        assert "Options:" in output
        assert "Commands:" in output

        # Check that specific options are mentioned
        assert "--latitude" in output
        assert "--longitude" in output
        assert "--place" in output
        assert "--system" in output
        assert "--quiet" in output
        assert "--json" in output
        assert "--help" in output

        # Check that specific commands are mentioned
        assert "list" in output
        assert "verbose" in output
        assert "try" in output
        assert "horoscope" in output
        assert "settings" in output
        assert "places" in output
        assert "version" in output

    def test_version_command_output(self):
        """Test that version command output matches Perl structure."""
        runner = CliRunner()
        result = runner.invoke(cli, ["version"])

        assert result.exit_code == 0
        output = result.output

        # Check that version information is present
        assert "Panchanga Python Version" in output
        assert "Suryasiddhanta" in output
        assert "M. YANO and M. FUSHIMI" in output

    def test_settings_command_output(self):
        """Test that settings command output matches Perl structure."""
        runner = CliRunner()
        result = runner.invoke(cli, ["settings"])

        assert result.exit_code == 0
        output = result.output

        # Check that settings information is present
        assert "Current settings:" in output
        assert "Latitude:" in output
        assert "Longitude:" in output
        assert "System:" in output
        assert "Desantara:" in output

        # Check that default values are correct
        assert "23.2" in output  # Default latitude (Ujjain)
        assert "75.8" in output  # Default longitude (Ujjain)
        assert "surya" in output  # Default system

    def test_cli_argument_parsing_perl_parity(self):
        """Test that CLI argument parsing matches Perl behavior."""
        runner = CliRunner()

        # Test that place name overrides coordinates
        result = runner.invoke(cli, ["--place", "delhi", "--latitude", "50.0", "settings"])
        assert result.exit_code == 0
        assert "28.6" in result.output  # Delhi latitude, not 50.0

        # Test that explicit coordinates work
        result = runner.invoke(cli, ["--latitude", "30.0", "--longitude", "80.0", "settings"])
        assert result.exit_code == 0
        assert "30.0" in result.output
        assert "80.0" in result.output

        # Test that system selection works
        result = runner.invoke(cli, ["--system", "surya", "settings"])
        assert result.exit_code == 0
        assert "System: surya" in result.output

        result = runner.invoke(cli, ["--system", "panca", "settings"])
        assert result.exit_code == 0
        assert "System: panca" in result.output

    def test_cli_error_handling_perl_parity(self):
        """Test that CLI error handling matches Perl behavior."""
        runner = CliRunner()

        # Test invalid place name
        result = runner.invoke(cli, ["--place", "nonexistent", "settings"])
        assert result.exit_code == 1
        assert "Error:" in result.output
        assert "Unknown place" in result.output

        # Test invalid coordinates
        result = runner.invoke(cli, ["--latitude", "100", "settings"])
        assert result.exit_code == 2
        assert "Error:" in result.output

        result = runner.invoke(cli, ["--longitude", "200", "settings"])
        assert result.exit_code == 2
        assert "Error:" in result.output

        # Test invalid system
        result = runner.invoke(cli, ["--system", "invalid", "settings"])
        assert result.exit_code == 2
        assert "Error:" in result.output

    def test_cli_output_formats_perl_parity(self):
        """Test that CLI output formats match Perl behavior."""
        runner = CliRunner()

        # Test JSON output
        result = runner.invoke(cli, ["--json", "settings"])
        assert result.exit_code == 0
        assert '"latitude"' in result.output
        assert '"longitude"' in result.output
        assert '"system"' in result.output
        assert '"desantara"' in result.output

        # Test quiet mode
        result = runner.invoke(cli, ["--quiet", "--place", "delhi", "settings"])
        assert result.exit_code == 0
        assert (
            "Using coordinates for Delhi" not in result.output
        )  # Should be suppressed in quiet mode

        # Test normal mode
        result = runner.invoke(cli, ["--place", "delhi", "settings"])
        assert result.exit_code == 0
        assert "Using coordinates for Delhi" in result.output  # Should be shown in normal mode

    def test_cli_command_structure_perl_parity(self):
        """Test that CLI command structure matches Perl exactly."""
        runner = CliRunner()

        # Test that all main commands exist and work
        commands = [
            "list",
            "verbose",
            "try",
            "horoscope",
            "places",
            "settings",
            "version",
        ]

        for cmd in commands:
            if cmd == "try":
                result = runner.invoke(
                    cli,
                    [
                        cmd,
                        "1946",
                        "2",
                        "5",
                        "--paksa",
                        "sukla",
                        "--year-system",
                        "saka",
                    ],
                )
            elif cmd == "horoscope":
                result = runner.invoke(cli, [cmd, "2024 3 15 14 30"])
            elif cmd in ["list", "verbose"]:
                result = runner.invoke(cli, [cmd, "2024 3 15"])
            else:
                result = runner.invoke(cli, [cmd])

            assert result.exit_code == 0, (
                f"Command '{cmd}' failed with exit code {result.exit_code}"
            )
            assert len(result.output) > 0, f"Command '{cmd}' produced no output"

    def test_cli_examples_perl_parity(self):
        """Test that CLI examples from help work as expected."""
        runner = CliRunner()

        # Test example: Convert Vedic date to modern
        result = runner.invoke(
            cli, ["try", "1946", "2", "5", "--paksa", "sukla", "--year-system", "saka"]
        )
        assert result.exit_code == 0
        assert "Saka 1946" in result.output

        # Test example: Convert modern date to Vedic
        result = runner.invoke(cli, ["list", "2024 3 15"])
        assert result.exit_code == 0
        assert "2024" in result.output

        # Test example: Get detailed information for Delhi
        result = runner.invoke(cli, ["--place", "delhi", "verbose", "2024 3 15"])
        assert result.exit_code == 0
        assert "Using coordinates for Delhi" in result.output

        # Test example: Get detailed information with custom coordinates
        result = runner.invoke(
            cli, ["--latitude", "28.6", "--longitude", "77.2", "verbose", "2024 3 15"]
        )
        assert result.exit_code == 0

        # Test example: Calculate horoscope for Mumbai
        result = runner.invoke(cli, ["--place", "mumbai", "horoscope", "2024 3 15 14 30"])
        assert result.exit_code == 0
        assert "Using coordinates for Mumbai" in result.output

        # Test example: Show current settings
        result = runner.invoke(cli, ["settings"])
        assert result.exit_code == 0
        assert "Current settings:" in result.output

        # Test example: List available places
        result = runner.invoke(cli, ["places"])
        assert result.exit_code == 0
        assert "Available places:" in result.output
