import subprocess
import os

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.styles import Style

from rich.console import Console
from rich.panel import Panel
from rich import print

from kytin.core.context import Context
from kytin.core.executor import exec_command
from commands import COMMANDS

# -------------------------------
# Console
# -------------------------------
console = Console()

# -------------------------------
# Docker Config
# -------------------------------
CONTAINER_NAME = "kytin_container"
IMAGE_NAME = "kytin-kali"


# -------------------------------
# Docker Management
# -------------------------------
import os

def start_container():
    workspace = os.getcwd()

    # Check running container
    result = subprocess.run(
        f"docker ps --filter name={CONTAINER_NAME} --format '{{{{.Names}}}}'",
        shell=True,
        capture_output=True,
        text=True
    )

    if CONTAINER_NAME in result.stdout:
        return

    # Check stopped container
    result_all = subprocess.run(
        f"docker ps -a --filter name={CONTAINER_NAME} --format '{{{{.Names}}}}'",
        shell=True,
        capture_output=True,
        text=True
    )

    if CONTAINER_NAME in result_all.stdout:
        console.print("[cyan][+] Starting existing container...[/cyan]")
        subprocess.run(f"docker start {CONTAINER_NAME}", shell=True)
    else:
        console.print("[cyan][+] Creating new container...[/cyan]")

        subprocess.run(
            f"docker run -dit "
            f"--name {CONTAINER_NAME} "
            f"-v {workspace}:/workspace "
            f"{IMAGE_NAME}",
            shell=True
        )


# -------------------------------
# Command Handler
# -------------------------------
def handle_command(cmd, context):
    cmd = cmd.strip()

    # Remove accidental prompt prefix if present
    if cmd.startswith("kytin"):
        cmd = cmd.replace("kytin", "", 1).strip()

    if not cmd:
        return

    # Exit
    if cmd in ["exit", "quit"]:
        return "EXIT"
    
    # Handle cd command
    if cmd.startswith("cd"):
        parts = cmd.split()

        if len(parts) < 2:
            context.cwd = "/root"
        else:
            new_dir = parts[1]

            if new_dir.startswith("/"):
              context.cwd = new_dir
            else:
                context.cwd = f"{context.cwd}/{new_dir}"

        console.print(f"[cyan][+] Changed directory to {context.cwd}[/cyan]")
        return

    # Prevent misuse
    if cmd.startswith("nmap") and "set target" in cmd:
        console.print("[red][!] Do not mix 'set target' with nmap[/red]")
        console.print("[dim]Example:[/dim]")
        console.print("  set target 192.168.1.12")
        console.print("  nmap -p- 192.168.1.12")
        return

    # Command routing
    for name, command in COMMANDS.items():
        if cmd.startswith(name):
            command.run(cmd, context)
            return

    # Auto-append target for nmap
    if cmd.startswith("nmap") and context.target:
        if context.target not in cmd:
            cmd = f"{cmd} {context.target}"

    cmd = cmd.strip()
    # Default execution
    exec_command(cmd, context, message="Executing...")


# -------------------------------
# Main Shell
# -------------------------------
def main():
    # Banner
    console.print(Panel.fit(
        "[bold cyan]Kytin Offensive Shell[/bold cyan]\n"
        "[dim]v1.0 | Docker-powered Pentesting CLI[/dim]",
        border_style="cyan"
    ))

    start_container()

    # Context
    context = Context()

    # History
    history = FileHistory(".kytin_history")

    # Autocomplete
    commands = list(COMMANDS.keys()) + ["help", "exit", "quit"]
    completer = WordCompleter(commands, ignore_case=True)

    # Prompt Style
    style = Style.from_dict({
        "prompt": "bold green",
        "target": "yellow",
    })

    # Shell loop
    while True:
        try:
            # Prompt
            if context.target:
                prompt_text = [
                ("class:prompt", "kytin"),
                ("", "("),
                ("class:target", context.target),
                ("", ")"),
                ("", f"[{context.cwd}]> ")
            ]
            else:
                prompt_text = [
                ("class:prompt", "kytin"),
                ("", f"[{context.cwd}]> ")
            ]

            cmd = prompt(
                prompt_text,
                history=history,
                completer=completer,
                style=style
            )

            # Help
            if cmd.strip() == "help":
                console.print(Panel.fit("""
[bold]Available Commands[/bold]

[cyan]set target <target>[/cyan]   → Set target
[cyan]scan[/cyan]                  → Fast scan
[cyan]recon <target>[/cyan]        → Automated recon
[cyan]exit / quit[/cyan]           → Exit shell

[bold]Raw Commands[/bold]
nmap -p- <target>
""", border_style="green"))
                continue

            # Execute
            result = handle_command(cmd, context)

            if result == "EXIT":
                break

        except KeyboardInterrupt:
            console.print("\n[red][!] Interrupted[/red]")

    console.print("\n[bold red]Exiting Kytin Shell...[/bold red]")


# -------------------------------
# Entry Point
# -------------------------------
if __name__ == "__main__":
    main()