import math

from meshy.utils import (
    extract_emoji,
    haversine_distance,
    parse_shared_contact,
    parse_shared_location,
)

# ─── parse_shared_contact ─────────────────────────────────────


class TestParseSharedContact:
    def test_valid(self):
        key = "aa" * 32
        result = parse_shared_contact(f"<{key}:1:Alice>")
        assert result == (key, 1, "Alice")

    def test_with_spaces_in_name(self):
        key = "bb" * 32
        result = parse_shared_contact(f"<{key}:2:Bob Smith>")
        assert result == (key, 2, "Bob Smith")

    def test_invalid_format(self):
        assert parse_shared_contact("not a contact") is None

    def test_short_key(self):
        assert parse_shared_contact("<aabb:1:Test>") is None


# ─── parse_shared_location ────────────────────────────────────


class TestParseSharedLocation:
    def test_valid(self):
        result = parse_shared_location("50.123456, 14.456789")
        assert result is not None
        assert abs(result[0] - 50.123456) < 1e-6
        assert abs(result[1] - 14.456789) < 1e-6

    def test_negative_coords(self):
        result = parse_shared_location("-33.868820, 151.209290")
        assert result is not None

    def test_out_of_range_lat(self):
        assert parse_shared_location("100.0, 14.0") is None

    def test_out_of_range_lon(self):
        assert parse_shared_location("50.0, 200.0") is None

    def test_invalid_format(self):
        assert parse_shared_location("not coords") is None


# ─── haversine_distance ───────────────────────────────────────


class TestHaversineDistance:
    def test_same_point(self):
        assert haversine_distance(50.0, 14.0, 50.0, 14.0) == 0.0

    def test_prague_brno(self):
        d = haversine_distance(50.0755, 14.4378, 49.1951, 16.6068)
        assert 180 < d < 200  # ~186 km

    def test_antipodes(self):
        d = haversine_distance(0.0, 0.0, 0.0, 180.0)
        assert abs(d - math.pi * 6371.0) < 1.0


# ─── extract_emoji ────────────────────────────────────────────


class TestExtractEmoji:
    def test_no_emoji(self):
        assert extract_emoji("Hello") is None

    def test_empty(self):
        assert extract_emoji("") is None

    def test_smiley(self):
        assert extract_emoji("Node 😀 test") == "😀"

    def test_weather_symbol(self):
        assert extract_emoji("☀ Sunny") == "☀"

    def test_rocket(self):
        assert extract_emoji("🚀 Launch") == "🚀"
