"""
Security Analysis Module
Detects deauth attacks, rogue APs, weak encryption, evil twins, and security issues
"""

from scapy.all import *
from scapy.layers.dot11 import *
from collections import defaultdict


def detect_security_analysis(packets):
    """Detect security issues, attacks, and encryption weaknesses"""
    security = {
        'deauth_attacks': {'detected': False, 'total_deauth': 0, 'by_ap': {}, 'attack_threshold': 10},
        'disassoc_attacks': {'detected': False, 'total_disassoc': 0, 'by_ap': {}},
        'rogue_aps': {'detected': False, 'suspicious_aps': []},
        'weak_encryption': {'detected': False, 'networks': []},
        'evil_twin': {'detected': False, 'potential_twins': []},
        'open_networks': [],
        'wep_networks': [],
        'krack_indicators': {'detected': False, 'details': []},
        'not_detected_reason': {}
    }

    ssid_to_bssids = defaultdict(set)
    bssid_to_ssid = {}
    bssid_to_encryption = {}
    deauth_by_ap = defaultdict(int)
    disassoc_by_ap = defaultdict(int)

    for idx, pkt in enumerate(packets, 1):
        try:
            if pkt.haslayer(Dot11):
                dot11 = pkt[Dot11]

                # Deauthentication frames
                if pkt.haslayer(Dot11Deauth):
                    security['deauth_attacks']['total_deauth'] += 1
                    ap_mac = dot11.addr2  # Source (AP or attacker)
                    deauth_by_ap[ap_mac] += 1

                # Disassociation frames
                if pkt.haslayer(Dot11Disas):
                    security['disassoc_attacks']['total_disassoc'] += 1
                    ap_mac = dot11.addr2
                    disassoc_by_ap[ap_mac] += 1

            # Analyze encryption from beacons
            if pkt.haslayer(Dot11Beacon):
                ssid = None
                bssid = None
                encryption = 'Unknown'

                if pkt.haslayer(Dot11):
                    bssid = pkt[Dot11].addr3

                if pkt.haslayer(Dot11Elt):
                    elt = pkt[Dot11Elt]
                    rsn_found = False
                    wpa_found = False
                    privacy = False

                    while elt:
                        # SSID
                        if elt.ID == 0:
                            ssid = elt.info.decode('utf-8', errors='ignore')

                        # Capability Info (check privacy bit)
                        # Privacy is in Dot11Beacon.cap field
                        if pkt.haslayer(Dot11Beacon):
                            beacon = pkt[Dot11Beacon]
                            if hasattr(beacon, 'cap'):
                                privacy = bool(beacon.cap & 0x0010)  # Privacy bit

                        # RSN IE (WPA2/WPA3)
                        if elt.ID == 48:
                            rsn_found = True
                            encryption = 'WPA2/WPA3'

                        # WPA IE (Vendor Specific)
                        if elt.ID == 221 and len(elt.info) >= 4:
                            # Check for Microsoft WPA OUI
                            if elt.info[0:3] == b'\x00\x50\xf2' and elt.info[3] == 0x01:
                                wpa_found = True
                                if encryption == 'Unknown':
                                    encryption = 'WPA'

                        if hasattr(elt, 'payload'):
                            elt = elt.payload.getlayer(Dot11Elt)
                        else:
                            break

                    # Determine encryption type
                    if not privacy and not rsn_found and not wpa_found:
                        encryption = 'Open'
                        security['open_networks'].append({'ssid': ssid or 'Hidden', 'bssid': bssid})
                    elif privacy and not rsn_found and not wpa_found:
                        encryption = 'WEP'
                        security['wep_networks'].append({'ssid': ssid or 'Hidden', 'bssid': bssid})
                        security['weak_encryption']['detected'] = True
                        security['weak_encryption']['networks'].append({
                            'ssid': ssid or 'Hidden',
                            'bssid': bssid,
                            'encryption': 'WEP',
                            'severity': 'Critical'
                        })
                    elif wpa_found and not rsn_found:
                        encryption = 'WPA'
                        security['weak_encryption']['detected'] = True
                        security['weak_encryption']['networks'].append({
                            'ssid': ssid or 'Hidden',
                            'bssid': bssid,
                            'encryption': 'WPA',
                            'severity': 'High'
                        })

                    if ssid and bssid:
                        ssid_to_bssids[ssid].add(bssid)
                        bssid_to_ssid[bssid] = ssid
                        bssid_to_encryption[bssid] = encryption

            # KRACK indicator: Detect nonce reuse (simplified detection)
            if pkt.haslayer(EAPOL):
                # KRACK involves key reinstallation - simplified indicator
                security['krack_indicators']['detected'] = True
                if len(security['krack_indicators']['details']) < 3:
                    security['krack_indicators']['details'].append({
                        'packet': idx,
                        'note': 'EAPOL frame detected - manual verification needed for KRACK'
                    })

        except Exception:
            continue

    # Analyze deauth attacks (excessive deauth frames)
    for ap_mac, count in deauth_by_ap.items():
        if count >= security['deauth_attacks']['attack_threshold']:
            security['deauth_attacks']['detected'] = True
            security['deauth_attacks']['by_ap'][ap_mac] = count

    # Analyze disassoc attacks
    for ap_mac, count in disassoc_by_ap.items():
        if count >= 10:
            security['disassoc_attacks']['detected'] = True
            security['disassoc_attacks']['by_ap'][ap_mac] = count

    # Detect rogue APs and evil twins (same SSID, different BSSIDs)
    for ssid, bssids in ssid_to_bssids.items():
        if len(bssids) > 1:
            # Multiple BSSIDs with same SSID - could be legitimate (multi-AP network) or evil twin
            security['rogue_aps']['detected'] = True
            security['evil_twin']['detected'] = True

            security['rogue_aps']['suspicious_aps'].append({
                'ssid': ssid,
                'bssid_count': len(bssids),
                'bssids': list(bssids)
            })

            # Evil twin detection (same SSID, different encryption)
            encryptions = {bssid_to_encryption.get(b, 'Unknown') for b in bssids}
            if len(encryptions) > 1:
                security['evil_twin']['potential_twins'].append({
                    'ssid': ssid,
                    'reason': 'Different encryption methods',
                    'bssids': [{'bssid': b, 'encryption': bssid_to_encryption.get(b, 'Unknown')} for b in bssids]
                })

    # Add explanations
    if not security['deauth_attacks']['detected']:
        security['not_detected_reason']['deauth'] = (
            f"No deauthentication attack detected. Fewer than {security['deauth_attacks']['attack_threshold']} "
            "deauth frames per AP. Normal operation typically has very few deauth frames."
        )

    if not security['weak_encryption']['detected']:
        security['not_detected_reason']['weak_encryption'] = (
            "No weak encryption detected. All networks use WPA2/WPA3 or stronger encryption."
        )

    if not security['evil_twin']['detected']:
        security['not_detected_reason']['evil_twin'] = (
            "No evil twin APs detected. Each SSID has only one BSSID or consistent encryption."
        )

    return security
