"""
External Tool Dependency Checker

Verifies that external pentesting tools are installed and provides
installation instructions for missing tools.

Supports both Kali Linux (apt) and Ubuntu (mixed methods).
"""
import shutil
import os
from typing import Dict, List, Tuple, Optional


def detect_distro() -> str:
    """Detect the Linux distribution."""
    try:
        with open('/etc/os-release', 'r') as f:
            content = f.read().lower()
            if 'kali' in content:
                return 'kali'
            elif 'parrot' in content:
                return 'parrot'
            elif 'ubuntu' in content:
                return 'ubuntu'
            elif 'debian' in content:
                return 'debian'
    except FileNotFoundError:
        pass
    return 'unknown'


# Install methods for different distributions
# 'apt' = available via apt on both Kali and Ubuntu
# 'kali_only' = apt on Kali, alternative method on Ubuntu
# 'manual' = requires manual installation on all distros
EXTERNAL_TOOLS = {
    'reconnaissance': {
        'nmap': {
            'command': 'nmap',
            'install_kali': 'sudo apt install nmap',
            'install_ubuntu': 'sudo apt install nmap',
            'install_method': 'apt',
            'description': 'Network scanner for host/port discovery'
        },
        'theharvester': {
            'command': 'theHarvester',
            'install_kali': 'sudo apt install theharvester',
            'install_ubuntu': 'pip3 install --user git+https://github.com/laramies/theHarvester.git@4.4.4 && pip3 install --user aiomultiprocess aiosqlite pyppeteer uvloop netaddr certifi PyYAML censys aiohttp aiodns beautifulsoup4 requests shodan dnspython ujson lxml',
            'install_method': 'kali_only',
            'description': 'OSINT tool for gathering emails, names, subdomains'
        },
        'whois': {
            'command': 'whois',
            'install_kali': 'sudo apt install whois',
            'install_ubuntu': 'sudo apt install whois',
            'install_method': 'apt',
            'description': 'Domain registration information lookup'
        },
        'dnsrecon': {
            'command': 'dnsrecon',
            'install_kali': 'sudo apt install dnsrecon',
            'install_ubuntu': 'pipx install dnsrecon',
            'install_method': 'kali_only',
            'description': 'DNS enumeration and reconnaissance'
        },
    },
    'web_scanning': {
        'nuclei': {
            'command': 'nuclei',
            'install_kali': 'sudo apt install nuclei',
            'install_ubuntu': 'cd /tmp && curl -sL $(curl -s https://api.github.com/repos/projectdiscovery/nuclei/releases/latest | grep browser_download_url | grep linux_amd64.zip | cut -d \\\" -f 4) -o nuclei.zip && unzip -o nuclei.zip nuclei && sudo mv nuclei /usr/local/bin/ && rm nuclei.zip',
            'install_method': 'kali_only',
            'description': 'Fast vulnerability scanner using templates'
        },
        'gobuster': {
            'command': 'gobuster',
            'install_kali': 'sudo apt install gobuster',
            'install_ubuntu': 'wget -q https://github.com/OJ/gobuster/releases/download/v3.8.2/gobuster_Linux_x86_64.tar.gz -O /tmp/gobuster.tar.gz && tar -xzf /tmp/gobuster.tar.gz -C /tmp && sudo mv /tmp/gobuster /usr/local/bin/ && sudo chmod +x /usr/local/bin/gobuster && rm /tmp/gobuster.tar.gz',
            'install_method': 'kali_only',
            'description': 'Directory/file & DNS brute-forcing tool (v3.x required)'
        },
        'ffuf': {
            'command': 'ffuf',
            'install_kali': 'sudo apt install ffuf',
            'install_ubuntu': 'sudo apt install ffuf',
            'install_method': 'apt',
            'description': 'Fast web fuzzer for content discovery'
        },
        'wpscan': {
            'command': 'wpscan',
            'install_kali': 'sudo apt install wpscan',
            'install_ubuntu': 'sudo gem install wpscan',
            'install_method': 'kali_only',
            'description': 'WordPress vulnerability scanner'
        },
        'nikto': {
            'command': 'nikto',
            'install_kali': 'sudo apt install nikto',
            'install_ubuntu': 'sudo apt install nikto',
            'install_method': 'apt',
            'description': 'Web server vulnerability scanner'
        },
        'dalfox': {
            'command': 'dalfox',
            'install_kali': 'wget -q https://github.com/hahwul/dalfox/releases/download/v2.12.0/dalfox-linux-arm64.tar.gz -O /tmp/dalfox.tar.gz && tar -xzf /tmp/dalfox.tar.gz -C /tmp && sudo mv /tmp/dalfox-linux-arm64 /usr/local/bin/dalfox && sudo chmod +x /usr/local/bin/dalfox && rm /tmp/dalfox.tar.gz',
            'install_ubuntu': 'wget -q https://github.com/hahwul/dalfox/releases/download/v2.12.0/dalfox-linux-amd64.tar.gz -O /tmp/dalfox.tar.gz && tar -xzf /tmp/dalfox.tar.gz -C /tmp && sudo mv /tmp/dalfox-linux-amd64 /usr/local/bin/dalfox && sudo chmod +x /usr/local/bin/dalfox && rm /tmp/dalfox.tar.gz',
            'install_method': 'kali_only',
            'description': 'XSS vulnerability scanner'
        },
    },
    'exploitation': {
        'sqlmap': {
            'command': 'sqlmap',
            'install_kali': 'sudo apt install sqlmap',
            'install_ubuntu': 'sudo apt install sqlmap',
            'install_method': 'apt',
            'description': 'Automatic SQL injection exploitation tool'
        },
        'metasploit': {
            'command': 'msfconsole',
            'alt_commands': ['/opt/metasploit-framework/bin/msfconsole'],
            'install_kali': 'sudo apt install metasploit-framework',
            'install_ubuntu': 'sudo apt install -y postgresql postgresql-contrib && sudo systemctl enable postgresql && sudo systemctl start postgresql && curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > /tmp/msfinstall && chmod +x /tmp/msfinstall && sudo /tmp/msfinstall && rm /tmp/msfinstall',
            'install_method': 'kali_only',
            'description': 'Penetration testing framework',
            'dependencies': ['postgresql']
        },
        'searchsploit': {
            'command': 'searchsploit',
            'install_kali': 'sudo apt install exploitdb',
            'install_ubuntu': 'sudo git clone https://gitlab.com/exploit-database/exploitdb.git /opt/exploitdb && sudo ln -sf /opt/exploitdb/searchsploit /usr/local/bin/searchsploit',
            'install_method': 'kali_only',
            'description': 'Exploit database search tool'
        },
    },
    'credential_attacks': {
        'hydra': {
            'command': 'hydra',
            'install_kali': 'sudo apt install hydra',
            'install_ubuntu': 'sudo apt install hydra',
            'install_method': 'apt',
            'description': 'Network login brute-forcing tool'
        },
        'john': {
            'command': 'john',
            'install_kali': 'sudo apt install john',
            'install_ubuntu': 'sudo apt install john',
            'install_method': 'apt',
            'description': 'John the Ripper password cracker'
        },
        'hashcat': {
            'command': 'hashcat',
            'install_kali': 'sudo apt install hashcat',
            'install_ubuntu': 'sudo apt install hashcat',
            'install_method': 'apt',
            'description': 'Advanced password recovery tool'
        },
    },
    'windows_ad': {
        'enum4linux': {
            'command': 'enum4linux',
            'alt_commands': ['enum4linux-ng'],
            'install_kali': 'sudo apt install enum4linux',
            'install_ubuntu': 'pipx install git+https://github.com/cddmp/enum4linux-ng',
            'install_method': 'kali_only',
            'description': 'Windows/Samba enumeration tool'
        },
        'smbmap': {
            'command': 'smbmap',
            'install_kali': 'sudo apt install smbmap',
            'install_ubuntu': 'pipx install --force smbmap && pipx inject smbmap impacket',
            'install_method': 'kali_only',
            'description': 'SMB share enumeration tool'
        },
        'netexec': {
            'command': 'nxc',
            'install_kali': 'sudo apt install netexec',
            'install_ubuntu': 'pipx install git+https://github.com/Pennyw0rth/NetExec',
            'install_method': 'kali_only',
            'description': 'Swiss army knife for pentesting Windows/AD (formerly CrackMapExec)'
        },
        'impacket-scripts': {
            'command': 'GetNPUsers.py',
            'alt_commands': ['impacket-GetNPUsers', 'GetNPUsers'],
            'install_kali': 'sudo apt install python3-impacket',
            'install_ubuntu': 'pipx install impacket',
            'install_method': 'kali_only',
            'description': 'Collection of Python classes for network protocols'
        },
        'bloodhound': {
            'command': 'bloodhound-python',
            'install_kali': 'sudo apt install bloodhound.py',
            'install_ubuntu': 'pipx install bloodhound',
            'install_method': 'kali_only',
            'description': 'Active Directory relationship mapper'
        },
        'responder': {
            'command': 'responder',
            'install_kali': 'sudo apt install responder',
            'install_ubuntu': 'sudo git clone https://github.com/lgandx/Responder.git /opt/Responder && sudo ln -sf /opt/Responder/Responder.py /usr/local/bin/responder',
            'install_method': 'kali_only',
            'description': 'LLMNR, NBT-NS and MDNS poisoner'
        },
    },
}


def get_install_command(tool_info: dict, distro: Optional[str] = None) -> str:
    """Get the appropriate install command for the current distro."""
    if distro is None:
        distro = detect_distro()

    if distro in ('kali', 'parrot'):
        return tool_info.get('install_kali', tool_info.get('install', ''))
    else:
        return tool_info.get('install_ubuntu', tool_info.get('install_kali', ''))


def check_tool(command: str, alt_commands: list = None) -> bool:
    """Check if a tool is installed and in PATH."""
    if shutil.which(command) is not None:
        return True
    # Check alternative command names or absolute paths
    if alt_commands:
        for alt in alt_commands:
            # Check if it's an absolute path that exists and is executable
            if alt.startswith('/') and os.path.isfile(alt) and os.access(alt, os.X_OK):
                return True
            # Otherwise check in PATH
            if shutil.which(alt) is not None:
                return True
    return False


def check_all_tools() -> Dict[str, Dict[str, bool]]:
    """
    Check installation status of all external tools.

    Returns:
        {
            'reconnaissance': {
                'nmap': True,
                'theharvester': False,
                ...
            },
            ...
        }
    """
    results = {}

    for category, tools in EXTERNAL_TOOLS.items():
        results[category] = {}
        for tool_name, tool_info in tools.items():
            alt_commands = tool_info.get('alt_commands')
            results[category][tool_name] = check_tool(tool_info['command'], alt_commands)

    return results


def get_tool_stats() -> Tuple[int, int]:
    """
    Get summary statistics of installed tools.
    
    Returns:
        (installed_count, total_count)
    """
    status = check_all_tools()
    installed = sum(1 for category in status.values() for is_installed in category.values() if is_installed)
    total = sum(len(tools) for tools in EXTERNAL_TOOLS.values())
    return installed, total


def get_missing_tools(distro: Optional[str] = None) -> List[Dict]:
    """
    Get list of missing tools with installation instructions.

    Args:
        distro: Optional distro override ('kali', 'ubuntu', etc.)

    Returns:
        [
            {
                'name': 'nuclei',
                'category': 'web_scanning',
                'command': 'nuclei',
                'install': 'go install ...',
                'description': '...'
            },
            ...
        ]
    """
    if distro is None:
        distro = detect_distro()

    missing = []
    status = check_all_tools()

    for category, tools in EXTERNAL_TOOLS.items():
        for tool_name, tool_info in tools.items():
            if not status[category][tool_name]:
                missing.append({
                    'name': tool_name,
                    'category': category,
                    'command': tool_info['command'],
                    'install': get_install_command(tool_info, distro),
                    'install_method': tool_info.get('install_method', 'apt'),
                    'description': tool_info['description']
                })

    return missing


def get_tools_by_category(distro: Optional[str] = None) -> Dict[str, List[Dict]]:
    """
    Get all tools organized by category with installation status.

    Args:
        distro: Optional distro override ('kali', 'ubuntu', etc.)

    Returns:
        {
            'reconnaissance': [
                {
                    'name': 'nmap',
                    'installed': True,
                    'command': 'nmap',
                    'install': '...',
                    'description': '...'
                },
                ...
            ],
            ...
        }
    """
    if distro is None:
        distro = detect_distro()

    status = check_all_tools()
    organized = {}

    for category, tools in EXTERNAL_TOOLS.items():
        organized[category] = []
        for tool_name, tool_info in tools.items():
            organized[category].append({
                'name': tool_name,
                'installed': status[category][tool_name],
                'command': tool_info['command'],
                'install': get_install_command(tool_info, distro),
                'install_method': tool_info.get('install_method', 'apt'),
                'description': tool_info['description']
            })

    return organized


def get_category_name(category: str) -> str:
    """Get human-readable category name."""
    names = {
        'reconnaissance': '🔍 Reconnaissance',
        'web_scanning': '🌐 Web Scanning',
        'exploitation': '💥 Exploitation',
        'credential_attacks': '🔑 Credential Attacks',
        'windows_ad': '🪟 Windows/Active Directory'
    }
    return names.get(category, category.replace('_', ' ').title())
