# Copyright 2026, Jiri Eischmann <jiri@eischmann.cz> and the meshy contributors
# SPDX-License-Identifier: GPL-3.0-or-later

import math
import re
import unicodedata

from gi.repository import GLib

_URL_RE = re.compile(r'(https?://[^\s<>"\')\]]+)')
_SHARED_CONTACT_RE = re.compile(r"^<([0-9a-fA-F]{64}):(\d+):(.+)>$")
_SHARED_LOCATION_RE = re.compile(r"^(-?\d+\.\d+),\s*(-?\d+\.\d+)$")


def linkify(text: str) -> str:
    escaped = GLib.markup_escape_text(text)

    def _replace(m):
        url = m.group(1)
        trailing = ""
        while url and url[-1] in ".,;:!?":
            trailing = url[-1] + trailing
            url = url[:-1]
        return f'<a href="{url}">{url}</a>{trailing}'

    return _URL_RE.sub(_replace, escaped)


def parse_shared_contact(text: str) -> tuple[str, int, str] | None:
    m = _SHARED_CONTACT_RE.match(text.strip())
    if not m:
        return None
    return (m.group(1), int(m.group(2)), m.group(3))


def parse_shared_location(text: str) -> tuple[float, float] | None:
    m = _SHARED_LOCATION_RE.match(text.strip())
    if not m:
        return None
    lat, lon = float(m.group(1)), float(m.group(2))
    if -90 <= lat <= 90 and -180 <= lon <= 180:
        return (lat, lon)
    return None


def haversine_distance(lat1, lon1, lat2, lon2) -> float:
    """Return the great-circle distance in km between two points."""
    R = 6371.0
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (
        math.sin(dlat / 2) ** 2
        + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2
    )
    return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))


def extract_emoji(name: str) -> str | None:
    if not name:
        return None
    for char in name:
        cat = unicodedata.category(char)
        if cat == "So":
            return char
        cp = ord(char)
        if 0x1F600 <= cp <= 0x1F64F:
            return char
        if 0x1F300 <= cp <= 0x1F5FF:
            return char
        if 0x1F680 <= cp <= 0x1F6FF:
            return char
        if 0x1F900 <= cp <= 0x1F9FF:
            return char
        if 0x1FA00 <= cp <= 0x1FAFF:
            return char
        if 0x2600 <= cp <= 0x27BF:
            return char
        if 0xFE00 <= cp <= 0xFE0F:
            continue
        if cp == 0x200D:
            continue
    return None
