"""
CHRONOS Cryptographic Scanner
==============================

Comprehensive SSL/TLS and cryptographic configuration analysis tool.
Performs certificate chain validation, cipher suite analysis, key size
detection, and NIST PQC algorithm detection.
"""

import asyncio
import socket
import ssl
import re
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Tuple, Any
from pathlib import Path

from cryptography import x509
from cryptography.x509.oid import NameOID, ExtensionOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, ec
from cryptography.hazmat.backends import default_backend

from ..exceptions import SecurityError


class KeyAlgorithm(str, Enum):
    """Key algorithm types."""
    RSA = "RSA"
    ECC = "ECC"
    DSS = "DSS"
    DH = "DH"
    UNKNOWN = "UNKNOWN"


class CipherStrength(str, Enum):
    """Cipher strength classification."""
    WEAK = "weak"
    MODERATE = "moderate"
    STRONG = "strong"
    QUANTUM_RESISTANT = "quantum_resistant"


class TLSVersion(str, Enum):
    """TLS version enum."""
    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"
    UNKNOWN = "Unknown"


# NIST PQC Algorithms mapping
NIST_PQC_ALGORITHMS = {
    "ML-KEM": {
        "name": "CRYSTALS-Kyber",
        "type": "Key Encapsulation",
        "nist_status": "Standardized (FIPS 203)",
    },
    "ML-DSA": {
        "name": "CRYSTALS-Dilithium",
        "type": "Digital Signature",
        "nist_status": "Standardized (FIPS 204)",
    },
    "SLH-DSA": {
        "name": "SPHINCS+",
        "type": "Digital Signature",
        "nist_status": "Standardized (FIPS 205)",
    },
    "SPHINCS+": {
        "name": "SPHINCS+",
        "type": "Digital Signature",
        "nist_status": "Finalist",
    },
}

# Weak cipher suites to flag
WEAK_CIPHERS = {
    # NULL ciphers
    "NULL": CipherStrength.WEAK,
    # Export ciphers
    "EXPORT": CipherStrength.WEAK,
    # DES/3DES
    "DES": CipherStrength.WEAK,
    "3DES": CipherStrength.MODERATE,
    # RC4
    "RC4": CipherStrength.WEAK,
    "RC2": CipherStrength.WEAK,
    # MD5
    "MD5": CipherStrength.WEAK,
    # PSK without authentication
    "PSK": CipherStrength.MODERATE,
    # ANON (no authentication)
    "ANON": CipherStrength.WEAK,
    # CAMELLIA with weak modes
    "CAMELLIA_128": CipherStrength.MODERATE,
    # IDEA
    "IDEA": CipherStrength.MODERATE,
}

# Strong cipher indicators
STRONG_CIPHERS = {
    "AES-128": CipherStrength.STRONG,
    "AES-256": CipherStrength.STRONG,
    "ChaCha20": CipherStrength.STRONG,
    "CHACHA20": CipherStrength.STRONG,
}


@dataclass
class KeyInfo:
    """Key information details."""
    
    algorithm: KeyAlgorithm
    size: int
    is_weak: bool
    quantum_vulnerable: bool = True
    details: Dict[str, Any] = field(default_factory=dict)
    
    def __post_init__(self):
        """Determine quantum vulnerability and weakness."""
        if self.algorithm == KeyAlgorithm.RSA:
            # RSA < 2048 bits is weak
            self.is_weak = self.size < 2048
            self.quantum_vulnerable = True  # RSA is vulnerable to Shor's algorithm
            self.details["type"] = "RSA"
            self.details["shor_vulnerable"] = True
        elif self.algorithm == KeyAlgorithm.ECC:
            # ECC < 256 bits is weak
            self.is_weak = self.size < 256
            self.quantum_vulnerable = True  # ECC is vulnerable to Shor's algorithm
            self.details["type"] = "ECC"
            self.details["shor_vulnerable"] = True
        elif self.algorithm == KeyAlgorithm.DH:
            # DH < 2048 bits is weak
            self.is_weak = self.size < 2048
            self.quantum_vulnerable = True  # DH is vulnerable to discrete log attacks
            self.details["type"] = "Diffie-Hellman"


@dataclass
class CipherSuiteInfo:
    """Cipher suite information."""
    
    name: str
    strength: CipherStrength = CipherStrength.STRONG
    components: Dict[str, str] = field(default_factory=dict)
    vulnerabilities: List[str] = field(default_factory=list)
    
    def __post_init__(self):
        """Analyze cipher suite components."""
        self._analyze_strength()
    
    def _analyze_strength(self):
        """Analyze cipher suite strength."""
        for weak_term, strength in WEAK_CIPHERS.items():
            if weak_term in self.name.upper():
                self.strength = strength
                if strength == CipherStrength.WEAK:
                    self.vulnerabilities.append(f"Uses {weak_term} algorithm")
                return
        
        for strong_term, strength in STRONG_CIPHERS.items():
            if strong_term in self.name.upper():
                self.strength = strength
                return


@dataclass
class CertificateInfo:
    """SSL/TLS certificate information."""
    
    subject: str
    issuer: str
    subject_alt_names: List[str] = field(default_factory=list)
    serial_number: str = ""
    fingerprint: str = ""
    version: int = 3
    not_before: datetime = field(default_factory=datetime.now)
    not_after: datetime = field(default_factory=datetime.now)
    key_info: Optional[KeyInfo] = None
    signature_algorithm: str = "Unknown"
    is_self_signed: bool = False
    is_expired: bool = False
    days_until_expiry: int = 0
    
    def __post_init__(self):
        """Calculate expiry status."""
        now = datetime.utcnow()
        self.is_expired = now > self.not_after
        self.days_until_expiry = max(0, (self.not_after - now).days)


@dataclass
class SSLTLSInfo:
    """SSL/TLS connection information."""
    
    host: str
    port: int
    protocol_version: TLSVersion = TLSVersion.UNKNOWN
    cipher_suite: Optional[CipherSuiteInfo] = None
    certificate_chain: List[CertificateInfo] = field(default_factory=list)
    supported_versions: List[TLSVersion] = field(default_factory=list)
    vulnerabilities: List[str] = field(default_factory=list)
    
    def add_vulnerability(self, vuln: str):
        """Add a vulnerability finding."""
        if vuln not in self.vulnerabilities:
            self.vulnerabilities.append(vuln)


@dataclass
class PQCDetectionResult:
    """Post-Quantum Cryptography detection result."""
    
    found: bool = False
    algorithms: List[str] = field(default_factory=list)
    file_path: Optional[str] = None
    line_number: int = 0
    context: str = ""
    confidence: float = 0.0  # 0.0 to 1.0
    details: Dict[str, Any] = field(default_factory=dict)


class CryptoScanner:
    """
    Cryptographic Security Scanner.
    
    Performs comprehensive analysis of SSL/TLS configurations, certificates,
    cipher suites, and cryptographic implementations.
    """
    
    def __init__(self, timeout: int = 10, verbose: bool = False):
        """
        Initialize the crypto scanner.
        
        Args:
            timeout: Connection timeout in seconds
            verbose: Enable verbose logging
        """
        self.timeout = timeout
        self.verbose = verbose
        self.logger = self._setup_logger()
    
    def _setup_logger(self):
        """Setup logger (placeholder for actual logging)."""
        class SimpleLogger:
            def __init__(self, verbose):
                self.verbose = verbose
            
            def debug(self, msg):
                if self.verbose:
                    print(f"[DEBUG] {msg}")
            
            def info(self, msg):
                if self.verbose:
                    print(f"[INFO] {msg}")
            
            def warning(self, msg):
                print(f"[WARNING] {msg}")
            
            def error(self, msg):
                print(f"[ERROR] {msg}")
        
        return SimpleLogger(self.verbose)
    
    async def scan_host(self, host: str, port: int = 443) -> SSLTLSInfo:
        """
        Scan a host for SSL/TLS configuration.
        
        Args:
            host: Target hostname or IP
            port: Target port (default: 443)
        
        Returns:
            SSLTLSInfo with scan results
        
        Raises:
            SecurityError: If scan fails
        """
        self.logger.info(f"Scanning {host}:{port} for SSL/TLS configuration")
        
        ssl_info = SSLTLSInfo(host=host, port=port)
        
        try:
            # Get certificate chain
            cert_chain = await self._get_certificate_chain(host, port)
            ssl_info.certificate_chain = cert_chain
            
            # Get supported TLS versions
            supported = await self._get_supported_tls_versions(host, port)
            ssl_info.supported_versions = supported
            
            # Get cipher suite information
            cipher_info = await self._get_cipher_suite_info(host, port)
            ssl_info.cipher_suite = cipher_info
            
            # Detect protocol version (active negotiation)
            version = await self._detect_tls_version(host, port)
            ssl_info.protocol_version = version
            
            # Perform vulnerability checks
            ssl_info.vulnerabilities = self._check_vulnerabilities(ssl_info)
            
            self.logger.info(f"Scan completed for {host}:{port}")
            
        except Exception as e:
            self.logger.error(f"Failed to scan {host}:{port}: {str(e)}")
            ssl_info.add_vulnerability(f"Scan failed: {str(e)}")
        
        return ssl_info
    
    async def _get_certificate_chain(
        self, host: str, port: int
    ) -> List[CertificateInfo]:
        """
        Retrieve and analyze certificate chain.
        
        Args:
            host: Target host
            port: Target port
        
        Returns:
            List of CertificateInfo objects
        """
        chain = []
        
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            # Retrieve cert chain via SSL connection
            with socket.create_connection(
                (host, port), timeout=self.timeout
            ) as sock:
                with context.wrap_socket(sock, server_hostname=host) as ssock:
                    der_certs = ssock.getpeercert_chain()
            
            # Parse each certificate
            for der_cert in der_certs:
                cert = x509.load_der_x509_certificate(
                    der_cert, default_backend()
                )
                cert_info = self._parse_certificate(cert)
                chain.append(cert_info)
            
            self.logger.info(f"Retrieved {len(chain)} certificates from {host}:{port}")
            
        except Exception as e:
            self.logger.warning(f"Failed to retrieve certificate chain: {str(e)}")
        
        return chain
    
    def _parse_certificate(self, cert: x509.Certificate) -> CertificateInfo:
        """
        Parse X.509 certificate and extract information.
        
        Args:
            cert: X.509 certificate object
        
        Returns:
            CertificateInfo with parsed details
        """
        # Extract subject
        subject = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
        subject_str = subject[0].value if subject else "Unknown"
        
        # Extract issuer
        issuer = cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)
        issuer_str = issuer[0].value if issuer else "Unknown"
        
        # Extract SANs
        san_list = []
        try:
            san_ext = cert.extensions.get_extension_for_oid(
                ExtensionOID.SUBJECT_ALTERNATIVE_NAME
            )
            san_list = [name.value for name in san_ext.value]
        except x509.ExtensionNotFound:
            pass
        
        # Extract key information
        key_info = self._extract_key_info(cert.public_key())
        
        # Check if self-signed
        is_self_signed = cert.issuer == cert.subject
        
        # Get signature algorithm
        sig_alg = cert.signature_algorithm_oid._name
        
        # Calculate fingerprint
        fingerprint = cert.fingerprint(hashes.SHA256()).hex()
        
        cert_info = CertificateInfo(
            subject=str(subject_str),
            issuer=str(issuer_str),
            subject_alt_names=san_list,
            serial_number=hex(cert.serial_number),
            fingerprint=fingerprint,
            version=cert.version.value,
            not_before=cert.not_valid_before_utc,
            not_after=cert.not_valid_after_utc,
            key_info=key_info,
            signature_algorithm=sig_alg,
            is_self_signed=is_self_signed,
        )
        
        return cert_info
    
    def _extract_key_info(self, public_key) -> KeyInfo:
        """
        Extract and analyze public key information.
        
        Args:
            public_key: Public key object from cryptography library
        
        Returns:
            KeyInfo with analysis
        """
        if isinstance(public_key, rsa.RSAPublicKey):
            key_size = public_key.key_size
            return KeyInfo(
                algorithm=KeyAlgorithm.RSA,
                size=key_size,
                is_weak=key_size < 2048,
            )
        
        elif isinstance(public_key, ec.EllipticCurvePublicKey):
            key_size = public_key.curve.key_size
            return KeyInfo(
                algorithm=KeyAlgorithm.ECC,
                size=key_size,
                is_weak=key_size < 256,
                details={"curve": public_key.curve.name},
            )
        
        else:
            return KeyInfo(
                algorithm=KeyAlgorithm.UNKNOWN,
                size=0,
                is_weak=True,
            )
    
    async def _get_supported_tls_versions(
        self, host: str, port: int
    ) -> List[TLSVersion]:
        """
        Detect supported TLS versions via banner grabbing.
        
        Args:
            host: Target host
            port: Target port
        
        Returns:
            List of supported TLS versions
        """
        supported = []
        
        # Try common TLS versions
        tls_versions = [
            (ssl.PROTOCOL_TLSv1, TLSVersion.TLS_1_0),
            (ssl.PROTOCOL_TLSv1_1, TLSVersion.TLS_1_1),
            (ssl.PROTOCOL_TLSv1_2, TLSVersion.TLS_1_2),
        ]
        
        # TLS 1.3 is available in Python 3.10+
        try:
            tls_versions.append((ssl.PROTOCOL_TLS_CLIENT, TLSVersion.TLS_1_3))
        except AttributeError:
            pass
        
        for proto, version in tls_versions:
            try:
                context = ssl.SSLContext(proto)
                context.check_hostname = False
                context.verify_mode = ssl.CERT_NONE
                
                with socket.create_connection(
                    (host, port), timeout=self.timeout
                ) as sock:
                    with context.wrap_socket(sock, server_hostname=host):
                        supported.append(version)
                        self.logger.debug(f"{host}:{port} supports {version.value}")
            
            except Exception as e:
                self.logger.debug(f"{version.value} not supported: {str(e)}")
        
        return supported
    
    async def _get_cipher_suite_info(
        self, host: str, port: int
    ) -> Optional[CipherSuiteInfo]:
        """
        Retrieve cipher suite information.
        
        Args:
            host: Target host
            port: Target port
        
        Returns:
            CipherSuiteInfo or None
        """
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            with socket.create_connection(
                (host, port), timeout=self.timeout
            ) as sock:
                with context.wrap_socket(sock, server_hostname=host) as ssock:
                    cipher_name = ssock.cipher()[0]
                    return CipherSuiteInfo(name=cipher_name)
        
        except Exception as e:
            self.logger.debug(f"Failed to get cipher suite: {str(e)}")
            return None
    
    async def _detect_tls_version(self, host: str, port: int) -> TLSVersion:
        """
        Detect active TLS version via banner grabbing.
        
        Args:
            host: Target host
            port: Target port
        
        Returns:
            Detected TLS version
        """
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            with socket.create_connection(
                (host, port), timeout=self.timeout
            ) as sock:
                with context.wrap_socket(sock, server_hostname=host) as ssock:
                    version = ssock.version()
                    
                    # Map to TLSVersion enum
                    version_map = {
                        "TLSv1": TLSVersion.TLS_1_0,
                        "TLSv1.1": TLSVersion.TLS_1_1,
                        "TLSv1.2": TLSVersion.TLS_1_2,
                        "TLSv1.3": TLSVersion.TLS_1_3,
                    }
                    
                    return version_map.get(version, TLSVersion.UNKNOWN)
        
        except Exception as e:
            self.logger.debug(f"Failed to detect TLS version: {str(e)}")
            return TLSVersion.UNKNOWN
    
    def _check_vulnerabilities(self, ssl_info: SSLTLSInfo) -> List[str]:
        """
        Check for cryptographic vulnerabilities.
        
        Args:
            ssl_info: SSLTLSInfo to analyze
        
        Returns:
            List of identified vulnerabilities
        """
        vulns = []
        
        # Check protocol version
        if ssl_info.protocol_version in [
            TLSVersion.SSL_2_0,
            TLSVersion.SSL_3_0,
            TLSVersion.TLS_1_0,
            TLSVersion.TLS_1_1,
        ]:
            vulns.append(f"Insecure protocol version: {ssl_info.protocol_version.value}")
        
        # Check supported versions
        for version in ssl_info.supported_versions:
            if version in [
                TLSVersion.SSL_2_0,
                TLSVersion.SSL_3_0,
                TLSVersion.TLS_1_0,
                TLSVersion.TLS_1_1,
            ]:
                vulns.append(f"Server supports deprecated version: {version.value}")
        
        # Check cipher suite
        if ssl_info.cipher_suite:
            if ssl_info.cipher_suite.strength == CipherStrength.WEAK:
                vulns.append(
                    f"Weak cipher suite in use: {ssl_info.cipher_suite.name}"
                )
            vulns.extend(ssl_info.cipher_suite.vulnerabilities)
        
        # Check certificate chain
        for i, cert in enumerate(ssl_info.certificate_chain):
            # Check expiry
            if cert.is_expired:
                vulns.append(f"Certificate {i} is expired")
            elif cert.days_until_expiry < 30:
                vulns.append(
                    f"Certificate {i} expires in {cert.days_until_expiry} days"
                )
            
            # Check key strength
            if cert.key_info and cert.key_info.is_weak:
                vulns.append(
                    f"Certificate {i} uses weak key: "
                    f"{cert.key_info.algorithm.value} {cert.key_info.size} bits"
                )
                vulns.append(
                    f"Certificate {i} is vulnerable to quantum attacks (Shor's algorithm)"
                )
            
            # Check self-signed
            if i == 0 and cert.is_self_signed:
                vulns.append("Server certificate is self-signed")
        
        return vulns
    
    def scan_ssl_banner(self, host: str, port: int = 443) -> Dict[str, str]:
        """
        Grab SSL/TLS banner to detect server information.
        
        Args:
            host: Target host
            port: Target port
        
        Returns:
            Dictionary with banner information
        """
        banner = {"host": host, "port": port}
        
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            with socket.create_connection(
                (host, port), timeout=self.timeout
            ) as sock:
                with context.wrap_socket(sock, server_hostname=host) as ssock:
                    # Get OpenSSL version
                    banner["openssl_version"] = ssl.OPENSSL_VERSION
                    banner["protocol_version"] = ssock.version()
                    banner["cipher"] = ssock.cipher()[0]
                    banner["cipher_bits"] = ssock.cipher()[2]
        
        except Exception as e:
            banner["error"] = str(e)
        
        return banner
    
    def detect_pqc_in_config(self, config_path: str) -> List[PQCDetectionResult]:
        """
        Detect NIST PQC algorithms in configuration files.
        
        Args:
            config_path: Path to configuration file or directory
        
        Returns:
            List of PQCDetectionResult objects
        """
        results = []
        path = Path(config_path)
        
        if path.is_file():
            results.extend(self._scan_file_for_pqc(path))
        elif path.is_dir():
            for file_path in path.rglob("*"):
                if file_path.is_file() and self._is_config_file(file_path):
                    results.extend(self._scan_file_for_pqc(file_path))
        
        return results
    
    def _scan_file_for_pqc(self, file_path: Path) -> List[PQCDetectionResult]:
        """
        Scan a single file for PQC algorithm references.
        
        Args:
            file_path: Path to file
        
        Returns:
            List of detection results
        """
        results = []
        
        try:
            with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
                for line_num, line in enumerate(f, 1):
                    for pqc_name, pqc_info in NIST_PQC_ALGORITHMS.items():
                        if pqc_name.lower() in line.lower():
                            result = PQCDetectionResult(
                                found=True,
                                algorithms=[pqc_info["name"]],
                                file_path=str(file_path),
                                line_number=line_num,
                                context=line.strip(),
                                confidence=0.9,
                                details=pqc_info,
                            )
                            results.append(result)
                            self.logger.info(
                                f"Found {pqc_info['name']} in {file_path}:{line_num}"
                            )
        
        except Exception as e:
            self.logger.warning(f"Failed to scan {file_path}: {str(e)}")
        
        return results
    
    def _is_config_file(self, path: Path) -> bool:
        """
        Check if file is a configuration file.
        
        Args:
            path: Path to file
        
        Returns:
            True if file is likely a config file
        """
        config_extensions = {
            ".yaml", ".yml", ".json", ".toml", ".xml", ".conf",
            ".config", ".cfg", ".ini", ".txt"
        }
        config_names = {"config", "settings", "deployment", "kubernetes"}
        
        return (
            path.suffix in config_extensions or
            path.stem in config_names or
            "config" in path.name.lower()
        )
    
    def analyze_rsa_key(self, key_size: int) -> Dict[str, Any]:
        """
        Analyze RSA key strength.
        
        Args:
            key_size: Key size in bits
        
        Returns:
            Analysis results
        """
        analysis = {
            "key_size": key_size,
            "is_weak": key_size < 2048,
            "quantum_vulnerable": True,
            "recommendations": [],
        }
        
        if key_size < 1024:
            analysis["recommendations"].append("Critical: Upgrade to at least 2048-bit RSA")
        elif key_size < 2048:
            analysis["recommendations"].append("Upgrade to 2048-bit or larger RSA")
        elif key_size < 4096:
            analysis["recommendations"].append("Consider upgrading to 4096-bit RSA")
        
        analysis["recommendations"].append(
            "Vulnerable to quantum attacks (Shor's algorithm). "
            "Plan transition to post-quantum algorithms like ML-KEM (CRYSTALS-Kyber)"
        )
        
        return analysis
    
    def analyze_ecc_key(self, curve_name: str, key_size: int) -> Dict[str, Any]:
        """
        Analyze ECC key strength.
        
        Args:
            curve_name: Elliptic curve name (e.g., 'secp256r1')
            key_size: Key size in bits
        
        Returns:
            Analysis results
        """
        analysis = {
            "curve": curve_name,
            "key_size": key_size,
            "is_weak": key_size < 256,
            "quantum_vulnerable": True,
            "recommendations": [],
        }
        
        if key_size < 256:
            analysis["recommendations"].append(f"Upgrade to at least P-256 ({256}-bit)")
        elif key_size < 384:
            analysis["recommendations"].append("Consider upgrading to P-384 or P-521")
        
        analysis["recommendations"].append(
            "Vulnerable to quantum attacks (Shor's algorithm). "
            "Plan transition to post-quantum algorithms like ML-KEM (CRYSTALS-Kyber)"
        )
        
        return analysis


class CipherSuiteAnalyzer:
    """Specialized analyzer for cipher suite configurations."""
    
    # Recommended cipher suites for TLS 1.2+
    RECOMMENDED_CIPHERS = [
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        "TLS_AES_256_GCM_SHA384",  # TLS 1.3
        "TLS_AES_128_GCM_SHA256",  # TLS 1.3
        "TLS_CHACHA20_POLY1305_SHA256",  # TLS 1.3
    ]
    
    @staticmethod
    def is_cipher_weak(cipher_name: str) -> bool:
        """Check if cipher suite is weak."""
        weak_patterns = [
            "NULL", "EXPORT", "DES", "RC4", "RC2", "MD5",
            "ANON", "IDEA", "PSK"
        ]
        return any(pattern in cipher_name.upper() for pattern in weak_patterns)
    
    @staticmethod
    def is_cipher_recommended(cipher_name: str) -> bool:
        """Check if cipher suite is recommended."""
        return any(
            rec in cipher_name.upper()
            for rec in ["ECDHE", "AES", "GCM", "CHACHA20", "POLY1305"]
        )
    
    @staticmethod
    def get_cipher_recommendations(
        current_ciphers: List[str],
    ) -> Dict[str, List[str]]:
        """
        Get recommendations for cipher suite improvements.
        
        Args:
            current_ciphers: Current cipher suites in use
        
        Returns:
            Dictionary with recommendations
        """
        weak = [c for c in current_ciphers if CipherSuiteAnalyzer.is_cipher_weak(c)]
        strong = [c for c in current_ciphers if not CipherSuiteAnalyzer.is_cipher_weak(c)]
        
        return {
            "weak_ciphers": weak,
            "strong_ciphers": strong,
            "recommended": CipherSuiteAnalyzer.RECOMMENDED_CIPHERS,
            "missing": [
                c for c in CipherSuiteAnalyzer.RECOMMENDED_CIPHERS
                if c not in current_ciphers
            ],
        }
