from __future__ import annotations

from .numeric import safe_int

# ----------------------------
# Direct port → friendly phrase
# ----------------------------
PORT_TO_PHRASE_EN = {
    80: "a web service (HTTP)",
    443: "a secure web service (HTTPS)",
    8080: "a proxy or alternative web service",
    8443: "an alternative secure web service",

    20: "a file transfer service (FTP-data)",
    21: "a file transfer service (FTP)",
    69: "a file transfer service (TFTP)",
    445: "a file sharing service (SMB)",

    22: "a remote access service (SSH)",
    23: "a remote access service (Telnet)",
    3389: "a remote desktop service (RDP)",
    5900: "a remote desktop service (VNC)",

    53: "a name resolution service (DNS)",
    161: "a network management service (SNMP)",
    162: "a network management service (SNMP-Trap)",

    25: "an email service (SMTP)",
    110: "an email service (POP3)",
    143: "an email service (IMAP)",
    465: "a secure email service (SMTPS)",
    587: "an email submission service (SMTP)",
    993: "a secure email service (IMAPS)",
    995: "a secure email service (POP3S)",

    389: "a directory service (LDAP)",
    636: "a secure directory service (LDAPS)",
    88:  "an authentication service (Kerberos)",

    1433: "a database service (MS SQL Server)",
    1521: "a database service (Oracle DB)",
    3306: "a database service (MySQL)",
    5432: "a database service (PostgreSQL)",
    27017: "a database service (MongoDB)",

    500: "a VPN service (IPSec IKE)",
    1701: "a VPN service (L2TP)",
    1723: "a VPN service (PPTP)",
    1194: "a VPN service (OpenVPN)",

    5060: "a VoIP service (SIP)",
    5222: "an instant messaging service (XMPP)",
}

# Some useful fallbacks (not explicitly listed in the mapping)
WEB_ALT_PORTS = {8000, 8001}  # 8080/8443 are already mapped above
MEDIA_RTP_LOW, MEDIA_RTP_HIGH = 16384, 32767


def src_port_category(port) -> str:
    """
    Returns a human-readable category name for a source port number.
    """
    p = safe_int(port, -1)
    if p == 0:
        return "a system port"
    if 1 <= p <= 1023:
        return "a well-known port"
    if 1024 <= p <= 49151:
        return "a registered port"
    if 49152 <= p <= 65535:
        return "an ephemeral port"
    return "an invalid port"


def dst_service_phrase(port) -> str:
    """
    Returns a user-friendly phrase for the destination service based on the port number.
    Uses direct mapping; if not found, applies reasonable fallbacks.
    """
    p = safe_int(port, -1)
    if not (0 <= p <= 65535):
        return "an invalid service"

    # 1) direct mapping
    phrase = PORT_TO_PHRASE_EN.get(p)
    if phrase:
        return phrase

    # 2) fallback for common alternative web ports
    if p in WEB_ALT_PORTS:
        return "an alternative web service"

    # 3) fallback for real-time media streams (RTP/RTCP)
    if MEDIA_RTP_LOW <= p <= MEDIA_RTP_HIGH:
        return "a real-time media transport service (RTP/RTCP)"

    # 4) default
    return "an unidentified service"
