#!/usr/bin/env python3
# coded by:
# ┏━┃┏━┃┏━┛┏━┃┏━ ┏━┛┏━┛┃  ┏━┃
# ┏━┃┏┏┛┃  ┏━┃┃ ┃┃ ┃┏━┛┃  ┃ ┃
# ┛ ┛┛ ┛━━┛┛ ┛┛ ┛━━┛━━┛━━┛━━┛
#------------------------------------------

import sys
import os
import subprocess
import tempfile
import urllib.request
import re
import shutil
import importlib
import getpass
import warnings
import locale
import platform
import psutil
import json

try:
    from .config import (
        VERSION, HISTORY_FILE, MEDIA_DIR,
        IS_WINDOWS
    )
except ImportError:
    from modules.config import (
        VERSION, HISTORY_FILE, MEDIA_DIR,
        IS_WINDOWS
    )
from utils import (
    spinner_start, spinner_stop, format_in_box_markdown, clean_shell_input
)
try:
    from .ai import nekoAI, getReply
    from .media import open_file, genVideo, editImage, genImage
    from .chats import get_session_id, reset_history
except ImportError:
    from modules.ai import nekoAI, getReply
    from modules.media import open_file, genVideo, editImage, genImage
    from modules.chats import get_session_id, reset_history
from colorama import Fore, Style, init
warnings.filterwarnings("ignore", category=DeprecationWarning)
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

init(autoreset=True)

def ensure_pip():
    if shutil.which("pip") is None:
        print("\n\nAyo, pip was not found in PATH. Please install python-pip and ensure pip is available, so I can install sum required packages to take off, bro 🥀\n\n.")
        sys.exit(1)

def ensure_package(import_name, pip_name=None):
    pip_name = pip_name or import_name
    try:
        importlib.import_module(import_name)
    except ImportError:
        print("[⮾] MISSING MODULE!")
        print(f"⬣ Installing missing dependency 🞛⮞ {pip_name}")
        subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name,"--break-system-packages"])

def version_tuple(version):
    return tuple(int(part) for part in re.findall(r"\d+", version or "0"))

def fetch_latest_pypi_version():
    try:
        with urllib.request.urlopen("https://pypi.org/pypi/nekocli/json", timeout=5) as response:
            payload = json.loads(response.read().decode("utf-8"))
            latest = payload.get("info", {}).get("version", "").strip()
            return latest or None
    except Exception:
        return None

def is_git_checkout():
    repo_root = ROOT_DIR
    return os.path.isdir(os.path.join(repo_root, ".git"))

def update_from_git_pull():
    repo_root = ROOT_DIR
    if shutil.which("git") is None:
        print(format_in_box_markdown(
            "🞫 git is not installed, cannot update checkout",
            color=Fore.RED
        ))
        return False

    result = subprocess.run(
        ["git", "-C", repo_root, "pull", "--ff-only"],
        text=True,
        capture_output=True
    )
    if result.returncode != 0:
        print(format_in_box_markdown(
            "🞫 Git update failed",
            color=Fore.RED
        ))
        error_output = (result.stderr or result.stdout or "").strip()
        if error_output:
            print(Fore.RED + error_output)
        return False

    output = (result.stdout or "").strip()
    if output:
        print(Fore.CYAN + output)
    print(format_in_box_markdown(
        "✔ Git checkout updated successfully!",
        color=Fore.GREEN
    ))
    return True

def update_from_pip():
    cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "nekocli", "--break-system-packages"]
    result = subprocess.run(cmd, text=True, capture_output=True)
    if result.returncode != 0:
        print(format_in_box_markdown(
            "🞫 Pip update failed",
            color=Fore.RED
        ))
        error_output = (result.stderr or result.stdout or "").strip()
        if error_output:
            print(Fore.RED + error_output)
        return False

    print(format_in_box_markdown(
        "✔ Pip package updated successfully!",
        color=Fore.GREEN
    ))
    return True

def checkupdts():
    try:
        import socket
        socket.create_connection(("pypi.org", 443), timeout=2)
    except OSError:
        return
    latest = fetch_latest_pypi_version()
    if not latest:
        return
    if version_tuple(latest) > version_tuple(VERSION):
        print("\n" + Fore.CYAN +  "="*40)
        print(Fore.CYAN + f"🐱 Update available: {VERSION} → {latest}")
        print(Fore.GREEN + "Run: neko -u to update to the latest version")
        print("="*40 + Fore.CYAN + "\n")

def neko_update():
    latest = fetch_latest_pypi_version()
    running_in_git_checkout = is_git_checkout()

    if latest:
        print(format_in_box_markdown(
            f"⚡ Latest release on PyPI: v{latest}",
            color=Fore.CYAN
        ))
    else:
        print(format_in_box_markdown(
            "⚠ Could not fetch latest release from PyPI",
            color=Fore.YELLOW
        ))

    if running_in_git_checkout:
        print(Fore.CYAN + "Detected git checkout install, running git pull...")
        success = update_from_git_pull()
    else:
        if latest and version_tuple(latest) <= version_tuple(VERSION):
            print(format_in_box_markdown(
                "✔ neko is already up to date",
                color=Fore.GREEN
            ))
            return

        print(Fore.CYAN + "Detected pip install, running pip upgrade...")
        success = update_from_pip()

    if not success:
        return

    print(Fore.CYAN + f"Current local version: v{VERSION}")
    print(Fore.GREEN + "Restart your shell/session if your old command is still cached.")

def print_help_menu():
    help_text = """
              ▒                                         ▓
             ▒███                                     ████
              ████▓▓                               ██████▓
              ███  ▓▓▓                         ▓███   ██
               ██     ▓▓▓▓                    ▓▓▓▓    ▓█
               ██       ▓▓▓▓               ▓▓▓▓       ██
                █▓         ▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓          █▓
                ██                                   ██
                ▓█▓                                  ██
                 ██                                 ▓██
                 ██                                 ██
                  █▓   █▓                           ██
                  ██   ███▓            ▒▓▓  ▓▓▒    ▓█
                  ▓█   █████▓            █████     ██
                   █▓  ███████▓          ████     ▓█▓
                   ██       ▓█▓▓░      ░▓▓  ▓▓▒   ██
                   ▓█▓                            ██
                    ██                           ██
                     █           ▒▓██▓▒          ██
                     ███          ▓███          ██
                      █▓▓▓          ▓        ▓▓▓▓
                         ▓▓▓▓             ▓▓▓▓        @𝗔𝗥𝗖𝗫𝗟⎔
                            ▓▓▓▓       █▓█▓
░███    ░██            ░██     ▓▓▓▓ ▓▓▓█      ░██████  ░██         ░██████
░████   ░██            ░██        ▓▓▓        ░██   ░██ ░██           ░██
░██░██  ░██  ░███████  ░██    ░██ ░███████  ░██        ░██           ░██
░██ ░██ ░██ ░██    ░██ ░██   ░██ ░██    ░██ ░██        ░██           ░██
░██  ░██░██ ░█████████ ░███████  ░██    ░██ ░██        ░██           ░██
░██   ░████ ░██        ░██   ░██ ░██    ░██  ░██   ░██ ░██           ░██
░██    ░███  ░███████  ░██    ░██ ░███████    ░██████  ░██████████ ░██████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
Usage: neko [options]

Options:
  -h, --help           Show this help menu and exit
  -v, --version        Display Neko current version
  -u, --update         Update Neko to the latest version
  -n, --neofetch       Show system information
  -r, --reset          Clear saved chat history
  -i, --interactive    Interactive chat mode (session saved at ~/neko/.token_neko)

Shell & Coding Modes:
  -w, --web            Use the web search module
  -c, --code           Code mode: get code with description + raw code output
  -s, --shell          Shell mode: get shell command with description + raw command
  -so, --shell-only    Only shell command: bare command without description

Media Modes:
  -f, --file           Provide an image file for Neko to analyze along with prompt
  -g, --generate       Image generation: ask Neko to create an image
  -gv, --generate-video Video generation: generate short 8s video from prompt
  -e, --edit           Image editing: edit an image with a custom prompt

Pentest Modes:
  -a, --auto           Autonomous agent: interactive chat + auto pentest + self-outputs (BETA)
  -x, --agent          Agent mode: manual pentest assistance with logs

If no flags are given, runs simple AI request.
Supports input via stdin for piped commands i.e:

$ cat logs.txt | neko analyze these logs.

"""
    spinner_stop()
    os.system("cls" if os.name == "nt" else "clear")
    print(Fore.CYAN + help_text)

def get_specs():
    def cmd(command):
        try:
            return subprocess.check_output(command, shell=True, stderr=subprocess.DEVNULL).decode().strip()
        except:
            return ""
    sys_type = platform.system()
    distro_str = "Unknown"
    if sys_type == "Linux":
        try:
            if os.path.exists("/etc/os-release"):
                with open("/etc/os-release") as f:
                    data = dict(re.findall(r'^([^=]+)=(.*)$', f.read(), re.M))
                    distro_name = data.get("PRETTY_NAME", "Linux").strip('"')
                    base = data.get("ID_LIKE", data.get("ID", "linux")).strip('"')
                    distro_str = f"{distro_name} (Base: {base})"
        except:
            distro_str = "Linux"
    elif sys_type == "Windows":
        distro_str = f"Windows {platform.release()} {platform.win32_edition()}"
    elif sys_type == "Darwin":
        distro_str = f"macOS {platform.mac_ver()[0]}"
    de = "CLI/Headless"
    for var in ["XDG_CURRENT_DESKTOP", "DESKTOP_SESSION"]:
        if os.environ.get(var):
            de = os.environ.get(var)
            break
    if de == "CLI/Headless" and sys_type == "Linux":
        for p, name in {"plasmashell": "KDE Plasma", "gnome-session": "GNOME", "xfce4-session": "XFCE"}.items():
            if shutil.which(p) or cmd(f"pgrep {p}"):
                de = name
                break
    elif sys_type == "Windows": de = "Windows Explorer"
    elif sys_type == "Darwin": de = "Aqua"
    try:
        lang, enc = locale.getlocale()
        locale_str = f"{lang}.{enc}" if lang else "Unknown"
    except:
        locale_str = "Unknown"
    managers = ["pacman", "yay", "paru", "apt", "brew", "dnf", "choco", "winget", "pip", "npm"]
    found_mgrs = ", ".join([m for m in managers if shutil.which(m)])
    cpu_name = ""
    if sys_type == "Linux":
        cpu_name = cmd("grep -m 1 'model name' /proc/cpuinfo | cut -d: -f2") or cmd("lscpu | grep 'Model name' | cut -d: -f2")
    elif sys_type == "Windows":
        cpu_name = cmd("wmic cpu get name").split('\n')[-1]
    elif sys_type == "Darwin":
        cpu_name = cmd("sysctl -n machdep.cpu.brand_string")
    cpu_name = (cpu_name or platform.processor()).strip()
    cores = psutil.cpu_count(logical=False)
    threads = psutil.cpu_count(logical=True)
    freq_info = psutil.cpu_freq()
    freq = f"{freq_info.max}MHz" if freq_info else "N/A"
    cpu_final = f"{cpu_name} | {cores} Cores / {threads} Threads @ {freq}"
    if sys_type == "Windows":
        gpu = cmd("wmic path win32_VideoController get name").split('\n')[-1].strip()
    elif sys_type == "Darwin":
        gpu = cmd("system_profiler SPDisplaysDataType | grep 'Chipset Model' | cut -d':' -f2").strip()
    else:
        gpu = cmd("lspci | grep -i vga | cut -d ':' -f3").strip()
    gpu = gpu if gpu else "Integrated Graphics/Unknown"
    mem = psutil.virtual_memory()
    ram_str = f"{round(mem.used / (1024**3), 2)}GB / {round(mem.total / (1024**3), 2)}GB"
    disk = psutil.disk_usage('/')
    storage_str = f"{round(disk.used / (1024**3), 2)}GB / {round(disk.total / (1024**3), 2)}GB"
    lines = [
        f"OS: {sys_type}",
        f"DISTRO: {distro_str}",
        f"DESKTOP ENVIRONMENT: {de}",
        f"LOCALE: {locale_str}",
        f"SHELL: {os.environ.get('SHELL') or os.environ.get('COMSPEC', 'unknown')}",
        f"PACKAGE MANAGERS: {found_mgrs}",
        "---",
        f"CPU: {cpu_final}",
        f"GPU: {gpu}",
        f"RAM: {ram_str} (used/total)",
        f"STORAGE: {storage_str} (used/total)"
    ]

    if hasattr(psutil, "sensors_battery"):
        bat = psutil.sensors_battery()
        if bat:
            lines.append(f"Battery: {bat.percent}% {'Charging' if bat.power_plugged else 'Discharging'}")

    return "\n".join(lines)

SYS_SPECS = get_specs()

def read_tty_line(prompt=""):
    try:
        return input(prompt)
    except EOFError:
        return None

def clear_history():
    spinner_stop()
    if os.path.exists(HISTORY_FILE):
            os.remove(HISTORY_FILE)
    reset_history()
    print("\n")
    print(format_in_box_markdown("[!] History cleared! ", color=Fore.CYAN))
    print("\n")

def prompt_user_choice(prompt_str, choices):
    valid_choices = {c.lower() for c in choices}
    print(f"{Fore.YELLOW}{prompt_str}{Style.RESET_ALL}", end=" ", flush=True)
    while True:
        try:
            choice = raw_input("")
            if choice is None:
                continue
            choice = choice.strip().lower()
            if not choice:
                continue
            if choice in valid_choices:
                return choice
            else:
                print(f"Please enter one of {valid_choices}: ", end="", flush=True)
        except Exception:
            while True:
                try:
                    choice = raw_input(f"Please enter one of {valid_choices}: ")
                    choice = choice.strip().lower()
                    if choice in valid_choices:
                        return choice
                except KeyboardInterrupt:
                    continue

def prompt_filename():
    while True:
        try:
            filename = raw_input("What will be the filename ? ").strip()
            if filename:
                return filename
            else:
                print(f"{Fore.RED}Filename cannot be empty. Please try again.{Style.RESET_ALL}")
        except KeyboardInterrupt:
            print(f"\n{Fore.RED}Save cancelled.{Style.RESET_ALL}")
            return None

def raw_input(prompt=""):
    print(prompt, end="", flush=True)
    try:
        with open('/dev/tty', 'r') as tty_fd:
            if IS_WINDOWS:
                import msvcrt
                buf = ""
                while True:
                    ch = msvcrt.getwch()
                    if ch in ("\r", "\n"):
                        print()
                        return buf
                    elif ch == "\x08":  # backspace
                        if buf:
                            buf = buf[:-1]
                            print("\b \b", end="", flush=True)
                    elif ch == "\x03":
                        raise KeyboardInterrupt
                    else:
                        buf += ch
                        print(ch, end="", flush=True)
            else:
                import termios
                import tty
                try:
                    import readline
                except ImportError:
                    pass
                fd = tty_fd.fileno()
                try:
                    old = termios.tcgetattr(fd)
                except Exception:
                    return input()
                buf = ""
                try:
                    tty.setcbreak(fd)
                    while True:
                        ch = tty_fd.read(1)
                        if ch in ("\n", "\r"):
                            print()
                            return buf
                        elif ch in ("\x7f", "\x08"):
                            if buf:
                                buf = buf[:-1]
                                print("\b \b", end="", flush=True)
                        elif ch == "\x03":
                            raise KeyboardInterrupt
                        else:
                            buf += ch
                            print(ch, end="", flush=True)
                finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, old)
    except KeyboardInterrupt:
        raise
    except Exception:
        try:
            return input()
        except EOFError:
            return None

def extract_raw_code(full_response):
    lines = full_response.strip().splitlines()
    cleaned_lines = []
    in_code_block = False
    for line in lines:
        if line.strip().startswith("```"):
            if not in_code_block:
                in_code_block = True
                continue
            else:
                in_code_block = False
                continue
        else:
            if in_code_block or not line.strip().startswith("```"):
                cleaned_lines.append(line)
    raw_code = "\n".join(cleaned_lines).strip()
    return raw_code

def extract_raw_commands(text: str) -> str:
    match = re.search(r"```(?:bash)?\s*(.*?)```", text, re.DOTALL)
    if not match:
        return ""

    command_block = match.group(1)
    lines = []
    for line in command_block.splitlines():
        cleaned = re.sub(r"^[\s│╭╰─]*", "", line)
        lines.append(cleaned.strip())
    command = " ".join(lines)
    command = command.replace("\\ ", "")
    command = re.sub(r"\s+", " ", command)

    return command.strip()

def run_shell_command(command):
    try:
        result = subprocess.run(command, shell=True, text=True, capture_output=True)
        return (result.returncode, result.stdout, result.stderr)
    except Exception as e:
        return (1, "", str(e))

def pentest_agent_mode(user_input):
    assistant_full = nekoAI(user_input, specs=SYS_SPECS, agent=True)
    if not assistant_full:
        print(f"{Fore.RED}No response from API, exiting.{Style.RESET_ALL}")
        sys.exit(1)
    spinner_stop()
    print(format_in_box_markdown(assistant_full, color=Fore.RED))
    raw_commands = extract_raw_commands(assistant_full)
    if raw_commands.strip():
        print(f"\n{Fore.YELLOW} COMMANDS TO RUN 🗱 :\n")
        print(format_in_box_markdown(raw_commands, color=Fore.GREEN))
    sys.exit(0)

def main():
    # required pkgs for neko here 
    REQUIRED_PACKAGES = {
        "requests": "requests",
        "colorama": "colorama",
        "psutil": "psutil",
        "requests_toolbelt": "requests-toolbelt",
    }
    ensure_pip()
    for mod, pip_name in REQUIRED_PACKAGES.items():
        ensure_package(mod, pip_name)

    args = sys.argv[1:]
    shell_mode = False
    only_command = False
    code_mode = False
    web_mode = False
    image_gen = False
    image_edit = False
    auto_mode = False
    video_gen = False
    interactive_mode = False
    reset_history_flag = False
    pentest_agent = False
    upload_mode = False
    new_args = []
    i = 0
    for arg in args:
        if arg in ("-r", "--reset"):
            reset_history_flag = True
            clear_history()
        elif arg in ("-u", "--update"):
            neko_update()
            sys.exit(0)
        elif arg in ("-v", "--version"):
            print("\n" + Fore.GREEN + f"   [ ⚡] v{VERSION} 😼   \n")
            sys.exit(0)
        elif arg in ("-h", "--help"):
            print_help_menu()
            sys.exit(0)
        elif arg in ("-n", "--neofetch"):
            print("\n\n")
            username = getpass.getuser()
            print(format_in_box_markdown(
                f"N E K O - F E T C H      |        [ {username} ]\n..............................\n\n{SYS_SPECS}",
                color=Fore.CYAN
            ))
            print("\n")
            sys.exit(0)
        elif arg in ("-s", "--shell"):
            shell_mode = True
        elif arg in ("-so", "--shell-only"):
            shell_mode = True
            only_command = True
        elif arg in ("-c", "--code"):
            code_mode = True
        elif arg in ("-w", "--web"):
            web_mode = True
        elif arg in ("-gv", "--generate-video"):
            video_gen = True
            videoprompt_parts = []
            j = i + 1
            while j < len(args) and not args[j].startswith('-'):
                videoprompt_parts.append(args[j])
                j += 1
            if not videoprompt_parts:
                print(f"\n\n{Fore.RED}[!] Error:\n⯁➤ -g flag requires a prompt for video generation{Style.RESET_ALL}\n\n")
                sys.exit(1)
            video_prompt = " ".join(videoprompt_parts)
        elif arg in ("-g", "--generate"):
            image_gen = True
            prompt_parts = []
            j = i + 1
            while j < len(args) and not args[j].startswith('-'):
                prompt_parts.append(args[j])
                j += 1
            if not prompt_parts:
                print(f"\n\n{Fore.RED}[!] Error:\n⯁➤ -g flag requires a prompt for image generation{Style.RESET_ALL}\n\n")
                sys.exit(1)
            image_prompt = " ".join(prompt_parts)
        elif arg in ("-e", "--edit-image"):
            image_edit = True
            if i + 1 >= len(args):
                print(f"\n\n{Fore.RED}[!] Error:\n⯁➤ -e flag requires an image path and a prompt for image edition{Style.RESET_ALL}\n\n")
                sys.exit(1)
            image_dir = args[i + 1]
            prompt_parts = []
            it = i + 2
            while it < len(args) and not args[it].startswith('-'):
                prompt_parts.append(args[it])
                it += 1
            if not prompt_parts:
                print(f"\n\n{Fore.RED}[!] Error:\n⯁➤ -e flag requires a prompt after the image path{Style.RESET_ALL}\n\n")
                sys.exit(1)
            edit_prompt = " ".join(prompt_parts)
        elif arg in ("-f", "--file"):
            upload_mode = True
            try:
                file_path = args[i + 1]
                i += 1

            except IndexError:
                print(f"\n\n{Fore.RED}[!] Error:\n⯁➤ -f flag requires a file path{Style.RESET_ALL}\n\n")
                sys.exit(1)
        elif arg in ("-a", "--auto"):
            auto_mode = True
        elif arg in ("-i", "--interactive"):
            interactive_mode = True
        elif arg in ("-x", "--agent"):
            pentest_agent = True

        else:
            new_args.append(arg)
    args = new_args
    user_input = " ".join(args).strip()

    if not sys.stdin.isatty():
        piped_data = sys.stdin.read().strip()
        if user_input:
            user_input += "\n\n" + piped_data
        else:
            user_input = piped_data

    if reset_history_flag:
        reset_history()
        sys.exit(0)
    if not user_input and not interactive_mode:
        spinner_stop()
        print_help_menu()
        sys.exit(0)

    if interactive_mode:
        spinner_start()
        get_session_id(agent=False)
        pending_question = user_input

        while True:
            if not pending_question:
                spinner_stop()
                print(format_in_box_markdown("Type your question:", color=Fore.YELLOW))
                try:
                    pending_question = raw_input("△ New Question: ").strip()
                except KeyboardInterrupt:
                    print(f"\n\n{Fore.RED}Process interrupted.")
                    sys.exit(0)
                if not pending_question:
                    print("Empty question, quitting.")
                    break

            spinner_start()
            try:
                reply = getReply(pending_question)
            except Exception as e:
                reply = f"Error: {e}"
            spinner_stop()
            print(format_in_box_markdown(reply))
            choice = prompt_user_choice(f">>  {Fore.YELLOW}[N]ew Question\n>>  [Q]uit\n\n{Fore.CYAN} ⯁➤ ", {'n', 'q'})
            if choice == 'q':
                print(f"\n{Fore.RED}ㅿ 𝙴 𝚡 𝚒 𝚝 𝚒 𝚗 𝚐 . . .\n")
                break
            else:
                try:
                    pending_question = raw_input("△ New Question: ").strip()
                except KeyboardInterrupt:
                    print(f"\n\n{Fore.RED}Process interrupted.")
                    sys.exit(0)
                if not pending_question:
                    print("Empty question, quitting.")
                    break
        sys.exit(0)
    if pentest_agent:
        spinner_start()
        if not user_input:
            print(f"{Fore.RED}🗱 Please provide a starting prompt for agent mode.{Style.RESET_ALL}")
            sys.exit(1)
        pentest_agent_mode(user_input)
        sys.exit(0)
    if upload_mode:
        spinner_start()
        if not user_input:
            print(f"{Fore.RED}[!] Error:\n⯁➤ provide a prompt when using -f <file>{Style.RESET_ALL}")
            sys.exit(1)
        try:
            result = nekoAI(user_input, endpoint="vision", upload=True, filePath=file_path)
        except FileNotFoundError:
            spinner_stop()
            print(format_in_box_markdown(f"You sure u got this right? Didn't found any file here in {file_path}", color=Fore.YELLOW) + "\n")
            sys.exit(1)
        spinner_stop()
        print(format_in_box_markdown(result))
        print("\n")
        sys.exit(0)
    if video_gen:
        print(format_in_box_markdown("Video will be sent in 5 minutes.\n" ,color=Fore.YELLOW))
        print(f"    Prompt for video gen:\n {Fore.CYAN}       {video_prompt} \n   ")
        vidresult = genVideo(video_prompt)
        if not vidresult:
            print(f"{Fore.RED}Video generation failed. Nothing to open.{Style.RESET_ALL}")
            sys.exit(1)
        print(f"\n{Fore.CYAN}DONE [!]\nF i l e  s a v e d  a t . . . . . {MEDIA_DIR}\n\n  ⬡ Opening video now . . .\n\n")
        open_file(vidresult)
        sys.exit(1)
    if image_gen:
        print(format_in_box_markdown("Image will be sent in 5 minutes.\n",color=Fore.YELLOW))
        print(f"     Prompt for image gen:\n {Fore.CYAN}       {image_prompt}\n\n")
        image = genImage(image_prompt)
        if not image:
            print(f"{Fore.RED}Image generation failed. Nothing to open.{Style.RESET_ALL}")
            sys.exit(1)
        print(f"\n{Fore.CYAN}DONE [!]\nF i l e  s a v e d  a t . . . . . {MEDIA_DIR}\n\n  ⬡ Opening image now . . .\n\n")
        open_file(image)
        sys.exit(1)
    if image_edit:
        print(format_in_box_markdown("Image will be sent in 5 minutes.\n",color=Fore.YELLOW))
        print(f"    Prompt for image edit:\n {Fore.CYAN}       {edit_prompt}\n")
        try:
            image = editImage(image_dir, edit_prompt)
        except FileNotFoundError:
            print(format_in_box_markdown(f"You sure u got this right? Didn't found any file here in {image_dir}", color=Fore.YELLOW) + "\n")
            sys.exit(1)
        if not image:
            print(f"{Fore.RED}Image edit failed. Nothing to open.{Style.RESET_ALL}")
            sys.exit(1)
        print(f"\n{Fore.CYAN}DONE [!]\nF i l e  s a v e d  a t . . . . . {MEDIA_DIR}\n\n  ⬡ Opening image now . . .\n\n")
        open_file(image)
        sys.exit(1)

    if auto_mode:
        spinner_start()

        if not user_input:
            print(f"{Fore.RED}Please provide a prompt for autonomous mode (-a).{Style.RESET_ALL}")
            sys.exit(1)

        current_prompt = user_input
        last_assistant_msg = ""
        raw_commands = ""

        while True:

            assistant_response = nekoAI(current_prompt, specs=SYS_SPECS, agent=True)

            if not assistant_response:
                break

            spinner_stop()
            print(format_in_box_markdown(assistant_response, color=Fore.RED))

            last_assistant_msg = assistant_response

            raw_commands = extract_raw_commands(assistant_response)

            if raw_commands.strip():
                print(format_in_box_markdown(raw_commands, color=Fore.GREEN))

            choice = prompt_user_choice(
                f"{Fore.YELLOW}--[ [R]un | [N]ew | [A]sk | [Q]uit ]--\n\n{Fore.CYAN} ⯁➤ ",
                {'r', 'n', 'a', 'q'}
            )

            if choice == 'r':

                lines = [line.strip() for line in raw_commands.splitlines() if line.strip()]

                if not lines:
                    print(f"{Fore.RED}No commands to run.{Style.RESET_ALL}")
                    continue

                log_file = os.path.join(tempfile.gettempdir(), "NekoLogs.txt")

                with open(log_file, "w", encoding="utf-8") as logf:
                    for cmd in lines:
                        print(f"{Fore.GREEN}Running: {cmd}{Style.RESET_ALL}")
                        retcode, out, err = run_shell_command(cmd)
                        logf.write(f"$ {cmd}\n")
                        logf.write(out)
                        logf.write(err)
                        logf.write("\n\n")
                        print(out)
                        if retcode != 0:
                            print(f"{Fore.RED}Command exited with code {retcode}{Style.RESET_ALL}")

                with open(log_file, "r", encoding="utf-8") as logf:
                    logs_content = logf.read()

                current_prompt = (
                    f"Previous analysis:\n{last_assistant_msg}\n\n"
                    f"Command outputs:\n{logs_content}\n\n"
                    f"Continue."
                )

                spinner_start()
                continue

            elif choice == 'n':
                spinner_start()
                continue

            elif choice == 'a':

                print(format_in_box_markdown("Ask your question:", color=Fore.CYAN))

                try:
                    new_q = raw_input("△ Question: ").strip()
                except KeyboardInterrupt:
                    print(f"\n\n{Fore.RED}Process interrupted.")
                    sys.exit(0)

                if not new_q:
                    print(f"{Fore.RED}Empty input, returning to main loop.{Style.RESET_ALL}")
                    continue

                current_prompt = (
                    f"{last_assistant_msg}\n\n"
                    f"User follow-up question:\n{new_q}"
                )

                spinner_start()
                continue

            else:
                print(format_in_box_markdown(f"\n\n{Fore.YELLOW}ㅿ 𝙴 𝚡 𝚒 𝚝 𝚒 𝚗 𝚐..."))
                clear_history()
                sys.exit(0)

    if shell_mode:
        spinner_start()
        while True:
            user_input_str = clean_shell_input(str(user_input))
            if not only_command:
                description = nekoAI(user_input_str,endpoint="shell-description")
                spinner_stop()
                print("\n" + format_in_box_markdown(description, color=Fore.RED) + "\n")
            spinner_start()
            command = nekoAI(user_input_str,specs=SYS_SPECS,endpoint="shell-command")
            command = command.strip()
            spinner_stop()
            print(format_in_box_markdown(command, color=Fore.GREEN) + "\n")

            choice = prompt_user_choice(f"{Fore.YELLOW}--[ [E]xecute | [R]emake | [A]bort ]--\n\n{Fore.CYAN} ⯁➤ ", {'e', 'r', 'a'})
            if choice == 'e':
                print(f"{Fore.GREEN}Executing command...{Style.RESET_ALL}")
                try:
                    subprocess.run(command, shell=True, check=True)
                except subprocess.CalledProcessError as e:
                    print(f"{Fore.RED}Command failed with exit code {e.returncode}{Style.RESET_ALL}")
                break
            elif choice == 'r':
                continue
            else:
                print(f"\n\n{Fore.YELLOW}ㅿ E x i t i n g . . . \n\n")
                break

    elif code_mode:
        spinner_start()
        while True:
            unformattedCode = nekoAI(user_input,endpoint="code", use_web=web_mode)
            raw_code = extract_raw_code(unformattedCode)
            spinner_stop()
            print(format_in_box_markdown(raw_code, color=Fore.GREEN) + "\n")

            choice = prompt_user_choice(f"{Fore.YELLOW}--[ [S]ave | [N]ew | [Q]uit ]--\n\n{Fore.CYAN} ⯁➤ ", {'s', 'n', 'q'})

            if choice == 's':
                filename = prompt_filename()
                if filename:
                    try:
                        with open(filename, 'w', encoding='utf-8') as f:
                            f.write(raw_code)
                        print(f"{Fore.GREEN}Code saved to '{filename}'{Style.RESET_ALL}")
                    except Exception as e:
                        print(f"{Fore.RED}Failed to save file: {e}{Style.RESET_ALL}")
                else:
                    print(f"{Fore.YELLOW}Save operation cancelled.{Style.RESET_ALL}")
                break

            elif choice == 'n':
                continue
            else:
                print(f"\n\n{Fore.YELLOW}ㅿ 𝙴 𝚡 𝚒 𝚝 𝚒 𝚗 g... \n\n")
                break

    else:
        spinner_start()
        while True:
            response = nekoAI(user_input, use_web=web_mode)
            spinner_stop()
            print(format_in_box_markdown(response))
            print("\n\n")
            break

if __name__ == "__main__":
    checkupdts()
    main()
