from __future__ import annotations

SSL_2_0 = 0x0002
SSL_3_0 = 0x0300
TLS_1_0 = 0x0301
TLS_1_1 = 0x0302
TLS_1_2 = 0x0303
TLS_1_3 = 0x0304

PROTOCOL_NAMES = {
    SSL_2_0: "SSL 2.0",
    SSL_3_0: "SSL 3.0",
    TLS_1_0: "TLS 1.0",
    TLS_1_1: "TLS 1.1",
    TLS_1_2: "TLS 1.2",
    TLS_1_3: "TLS 1.3",
}

CT_HANDSHAKE = 22
CT_ALERT = 21
CT_CHANGE_CIPHER_SPEC = 20
CT_APPLICATION_DATA = 23
CT_HEARTBEAT = 24

HS_CLIENT_HELLO = 1
HS_SERVER_HELLO = 2
HS_CERTIFICATE = 11
HS_SERVER_KEY_EXCHANGE = 12
HS_SERVER_HELLO_DONE = 14
HS_HELLO_RETRY_REQUEST = 6

EXT_SERVER_NAME = 0x0000
EXT_STATUS_REQUEST = 0x0005
EXT_SUPPORTED_GROUPS = 0x000a
EXT_EC_POINT_FORMATS = 0x000b
EXT_SIGNATURE_ALGORITHMS = 0x000d
EXT_HEARTBEAT = 0x000f
EXT_ALPN = 0x0010
EXT_SIGNED_CERT_TIMESTAMP = 0x0012
EXT_EXTENDED_MASTER_SECRET = 0x0017
EXT_SESSION_TICKET = 0x0023
EXT_SUPPORTED_VERSIONS = 0x002b
EXT_PSK_KEY_EXCHANGE_MODES = 0x002d
EXT_KEY_SHARE = 0x0033
EXT_RENEGOTIATION_INFO = 0xff01

NAMED_GROUPS = {
    0x0017: "secp256r1",
    0x0018: "secp384r1",
    0x0019: "secp521r1",
    0x001d: "x25519",
    0x001e: "x448",
    0x0100: "ffdhe2048",
    0x0101: "ffdhe3072",
    0x0102: "ffdhe4096",
    0x0103: "ffdhe6144",
    0x0104: "ffdhe8192",
    0x11ec: "X25519MLKEM768",
    0x11eb: "SecP256r1MLKEM768",
    0x6399: "X25519Kyber768Draft00",
    0x639a: "SecP256r1Kyber768Draft00",
}

PQC_GROUPS = {0x11ec, 0x11eb, 0x6399, 0x639a}

SIGNATURE_ALGORITHMS = {
    0x0401: "rsa_pkcs1_sha256",
    0x0501: "rsa_pkcs1_sha384",
    0x0601: "rsa_pkcs1_sha512",
    0x0403: "ecdsa_secp256r1_sha256",
    0x0503: "ecdsa_secp384r1_sha384",
    0x0603: "ecdsa_secp521r1_sha512",
    0x0804: "rsa_pss_rsae_sha256",
    0x0805: "rsa_pss_rsae_sha384",
    0x0806: "rsa_pss_rsae_sha512",
    0x0807: "ed25519",
    0x0808: "ed448",
    0x0809: "rsa_pss_pss_sha256",
    0x080a: "rsa_pss_pss_sha384",
    0x080b: "rsa_pss_pss_sha512",
}

# Common cipher suite ID → name (subset but covers everything we check).
CIPHER_SUITES: dict[int, str] = {
    # TLS 1.3
    0x1301: "TLS_AES_128_GCM_SHA256",
    0x1302: "TLS_AES_256_GCM_SHA384",
    0x1303: "TLS_CHACHA20_POLY1305_SHA256",
    0x1304: "TLS_AES_128_CCM_SHA256",
    0x1305: "TLS_AES_128_CCM_8_SHA256",
    # ECDHE-RSA AEAD
    0xc02f: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    0xc030: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
    0xcca8: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
    # ECDHE-ECDSA AEAD
    0xc02b: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    0xc02c: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
    0xcca9: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
    # ECDHE CBC (weak)
    0xc013: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
    0xc014: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
    0xc009: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
    0xc00a: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
    0xc027: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
    0xc028: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
    0xc023: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
    0xc024: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
    # DHE CBC (legacy)
    0x0033: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
    0x0039: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
    0x0067: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
    0x006b: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
    # DHE AEAD
    0x009e: "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
    0x009f: "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
    0xccaa: "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
    # RSA key exchange (no FS)
    0x009c: "TLS_RSA_WITH_AES_128_GCM_SHA256",
    0x009d: "TLS_RSA_WITH_AES_256_GCM_SHA384",
    0x002f: "TLS_RSA_WITH_AES_128_CBC_SHA",
    0x0035: "TLS_RSA_WITH_AES_256_CBC_SHA",
    0x003c: "TLS_RSA_WITH_AES_128_CBC_SHA256",
    0x003d: "TLS_RSA_WITH_AES_256_CBC_SHA384",
    # 3DES (SWEET32)
    0x000a: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
    0xc012: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
    0x0016: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
    # RC4
    0x0004: "TLS_RSA_WITH_RC4_128_MD5",
    0x0005: "TLS_RSA_WITH_RC4_128_SHA",
    0xc011: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
    0xc007: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
    # NULL
    0x0001: "TLS_RSA_WITH_NULL_MD5",
    0x0002: "TLS_RSA_WITH_NULL_SHA",
    0x003b: "TLS_RSA_WITH_NULL_SHA256",
    # EXPORT (FREAK)
    0x0008: "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
    0x0014: "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
    # Anonymous
    0x0018: "TLS_DH_anon_WITH_RC4_128_MD5",
    0x0034: "TLS_DH_anon_WITH_AES_128_CBC_SHA",
}

# Cipher-suite flag helpers: derived from names.
def cipher_has_fs(name: str) -> bool:
    return "ECDHE" in name or "DHE" in name

def cipher_is_aead(name: str) -> bool:
    return "GCM" in name or "CHACHA20_POLY1305" in name or "CCM" in name

def cipher_is_weak(name: str) -> bool:
    for bad in ("NULL", "EXPORT", "_DES_", "3DES", "RC4", "MD5", "anon"):
        if bad in name:
            return True
    return False

def cipher_is_cbc(name: str) -> bool:
    return "_CBC_" in name

def cipher_is_rc4(name: str) -> bool:
    return "RC4" in name

def cipher_is_3des(name: str) -> bool:
    return "3DES" in name or "_DES_EDE" in name
