import sqlite3
import random
import time

def load_server(ip):
    conn = sqlite3.connect("servers.db")
    cursor = conn.cursor()

    cursor.execute("SELECT id, difficulty FROM servers WHERE ip = ?", (ip,))
    row = cursor.fetchone()
    if not row:
        return None
    server_id, difficulty = row

    cursor.execute("SELECT id, path, is_locked FROM paths WHERE server_id = ?", (server_id,))
    path_rows = cursor.fetchall()

    file_system = {}
    locked_paths = set()
    files_content = {}

    # Создаём словарь путей, инициализируем пустые списки
    for path_id, path, is_locked in path_rows:
        if not path.startswith("/"):
            path = "/" + path
        file_system[path] = []
        if is_locked:
            locked_paths.add(path)

    # Добавляем файлы
    for path_id, path, _ in path_rows:
        if not path.startswith("/"):
            path = "/" + path
        cursor.execute("SELECT filename, content FROM files WHERE path_id = ?", (path_id,))
        for filename, content in cursor.fetchall():
            file_system[path].append(filename)
            full_path = path.rstrip("/") + "/" + filename
            files_content[full_path] = content

    # Добавляем поддиректории в списки файлов, чтобы ls показывал папки тоже
    for parent_path in file_system:
        # Поддиректории — это все пути, которые начинаются с parent_path + "/" и не равны parent_path
        # Для прямого потомка нужно, чтобы после parent_path был ровно один уровень
        subdirs = []
        for p in file_system.keys():
            if p == parent_path:
                continue
            if p.startswith(parent_path.rstrip("/") + "/"):
                # Отрезаем parent_path, смотрим есть ли один уровень папки
                rest = p[len(parent_path.rstrip("/"))+1:]
                if "/" not in rest:
                    subdirs.append(rest)
        # Добавляем поддиректории в список файлов (отмечая их как папки)
        for d in subdirs:
            if d not in file_system[parent_path]:
                file_system[parent_path].append(d + "/")  # добавляем слэш, чтобы видно было, что это папка

    conn.close()

    return {
        "ip": ip,
        "difficulty": difficulty,
        "file_system": file_system,
        "locked_paths": locked_paths,
        "files_content": files_content,
        "current_path": "/"
    }

def success(output_func, server_ref):
    server = server_ref
    output_func(f"\nВы взломали сервер {server['ip']}! Поздравляем!\n", "system")
    server_ref.clear()
    output_func("Вы отключены с сервера\n", 'system')


def handle_command(cmd, server_ref, output_func, clear_screen_callback, exit_callback):
    parts = cmd.strip().split()
    if not parts:
        return

    command = parts[0].lower()

    # Команды доступные без подключения
    if command == "help":
        output_func("Команды:\n", "system")
        output_func("  scan        — найти сервера\n", "system")
        output_func("  connect IP  — подключиться к серверу\n", "system")
        output_func("  ls          — список файлов (только при подключении)\n", "system")
        output_func("  cd <путь>   — переход в папку (только при подключении)\n", "system")
        output_func("  bruteforce <папка>   — попытка разблокировать папку\n", "system")
        output_func("  cat <файл>  — вывести содержимое файла (только при подключении)\n", "system")
        output_func("  back  — вернуться в предыдущий каталог\n", "system")
        output_func("  download  — скачать файл\n", "system")
        output_func("  delete  — удалить файл\n", "system")
        output_func("  clear       — очистить экран\n", "system")
        output_func("  exit        — выйти из игры\n", "system")
        return

    if command == "scan":
        if server_ref:
            output_func("Вы уже подключены к серверу. Отключитесь, чтобы сканировать.\n", "error")
            return
        conn = sqlite3.connect("servers.db")
        cursor = conn.cursor()
        cursor.execute("SELECT ip, difficulty FROM servers")
        rows = cursor.fetchall()
        conn.close()
        output_func("Обнаружены сервера:\n", "system")
        for ip, diff in rows:
            output_func(f"  {ip} (уровень сложности: {diff}/10)\n", "system")
        return

    if command == "connect":
        if len(parts) < 2:
            output_func("Использование: connect <ip>\n", "error")
            return
        ip = parts[1]
        new_server = load_server(ip)
        if not new_server:
            output_func(f"Сервер {ip} не найден.\n", "error")
            return
        server_ref.clear()
        server_ref.update(new_server)
        output_func(f"Успешно подключено к {ip}\n", "system")
        if ip == "192.168.1.5":
            output_func("Ваша цель прочитать файл secret.txt спрятанный где то в системе")
        elif ip == "192.168.1.193":
            output_func("Ваша цель скачать пароли пользователей")
        elif ip == "192.168.2.31":
            output_func("Ваша цель удалить сервер игры")
        return

    if command == "clear":
        clear_screen_callback()
        return

    if command == "exit":
        output_func("Выход из терминала...\n", "system")
        exit_callback()
        return

    # Команды, доступные только при подключении
    if not server_ref:
        if command in ["ls", "cd", "cat", "back", "bruteforce", 'download', 'delete']:
            output_func("Вы не подключены к серверу. Используйте connect <ip>\n", "error")
            return
        else:
            output_func("Неизвестная команда. Введите help для списка.\n", "error")
            return

    server = server_ref
    ip = server_ref.get("ip")
    current_path = server["current_path"]

    if ip == "192.168.1.5":
        if command == "back":
            if current_path == "/":
                output_func("Вы уже в корневом каталоге.\n", "system")
            else:
                parts = current_path.strip("/").split("/")
                parts.pop()  # убираем последний сегмент пути
                new_path = "/" + "/".join(parts) if parts else "/"
                server["current_path"] = new_path
                output_func(f"Вы вернулись в {new_path}\n", "system")
                return

        if command == "ls":
            files = server["file_system"].get(current_path, [])
            if not files:
                output_func("Содержимое: (пусто)\n", "system")
            else:
                output_func("Содержимое:\n" + "\n".join(f"  {f}" for f in files) + "\n", "system")
            return

        if command == "cd":
            if len(parts) < 2:
                output_func("Укажите папку. Пример: cd vault\n", "error")
                return
            target = parts[1]
            if not target.startswith("/"):
                target = current_path.rstrip("/") + "/" + target
            if target in server["locked_paths"]:
                output_func(f"Папка {target} заблокирована.\n", "error")
            elif target not in server["file_system"]:
                output_func(f"Папка {target} не найдена.\n", "error")
            else:
                server["current_path"] = target
                output_func(f"Вы перешли в {target}\n", "system")
            return
    
        if command == 'bruteforce':
            if len(parts) < 2:
                output_func("Укажите папку", 'error')
                return
            target = parts[1]
        # Приведём target к абсолютному пути, если нужно
            if not target.startswith('/'):
                target = server['current_path'].rstrip('/') + '/' + target

            if target not in server['locked_paths']:
                output_func("Папка не заблокирована.\n", 'system')
            else:
                opened = random.randint(1, 2)  # случайное 1 или 2
                if opened == 1:
                    # Успешно разблокируем — удаляем из locked_paths
                    server['locked_paths'].remove(target)
                    output_func('Папка разблокирована!\n', 'system')
                else:
                    output_func('Попытка bruteforce неудачна.\n', 'system')
            return

        if command == "cat":
            if len(parts) < 2:
                output_func("Использование: cat <имя_файла>\n", "error")
                return
            filename = parts[1]
            files = server["file_system"].get(current_path, [])
            if filename in files:
                full_path = current_path.rstrip("/") + "/" + filename
                content = server["files_content"].get(full_path, "(пустой файл)\n")
                output_func(f"{content}\n", "system")

                if filename == "secret.txt":
                    success(output_func, server_ref)
            else:
                output_func(f"Файл {filename} не найден.\n", "error")
            return

        output_func("Неизвестная команда. Введите help для списка.\n", "error")

    if ip == "192.168.2.31":
        if command == "back":
            if current_path == "/":
                output_func("Вы уже в корневом каталоге.\n", "system")
            else:
                parts = current_path.strip("/").split("/")
                parts.pop()  # убираем последний сегмент пути
                new_path = "/" + "/".join(parts) if parts else "/"
                server["current_path"] = new_path
                output_func(f"Вы вернулись в {new_path}\n", "system")
                return

        if command == "ls":
            files = server["file_system"].get(current_path, [])
            if not files:
                output_func("Содержимое: (пусто)\n", "system")
            else:
                output_func("Содержимое:\n" + "\n".join(f"  {f}" for f in files) + "\n", "system")
            return

        if command == "cd":
            if len(parts) < 2:
                output_func("Укажите папку. Пример: cd vault\n", "error")
                return
            target = parts[1]
            if not target.startswith("/"):
                target = current_path.rstrip("/") + "/" + target
            if target in server["locked_paths"]:
                output_func(f"Папка {target} заблокирована.\n", "error")
            elif target not in server["file_system"]:
                output_func(f"Папка {target} не найдена.\n", "error")
            else:
                server["current_path"] = target
                output_func(f"Вы перешли в {target}\n", "system")
            return
    
        if command == 'bruteforce':
            if len(parts) < 2:
                output_func("Укажите папку", 'error')
                return
            target = parts[1]
        # Приведём target к абсолютному пути, если нужно
            if not target.startswith('/'):
                target = server['current_path'].rstrip('/') + '/' + target

            if target not in server['locked_paths']:
                output_func("Папка не заблокирована.\n", 'system')
            else:
                opened = random.randint(1, 2)  # случайное 1 или 2
                if opened == 1:
                    # Успешно разблокируем — удаляем из locked_paths
                    server['locked_paths'].remove(target)
                    output_func('Папка разблокирована!\n', 'system')
                else:
                    output_func('Попытка bruteforce неудачна.\n', 'system')
            return

        if command == "cat":
            if len(parts) < 2:
                output_func("Использование: cat <имя_файла>\n", "error")
                return
            filename = parts[1]
            files = server["file_system"].get(current_path, [])
            if filename in files:
                full_path = current_path.rstrip("/") + "/" + filename
                content = server["files_content"].get(full_path, "(пустой файл)\n")
                output_func(f"{content}\n", "system")
            else:
                output_func(f"Файл {filename} не найден.\n", "error")
            return
        
        if command == "download":
            if len(parts) < 2:
                output_func("Использование: download <имя_файла>\n", "error")
                return
            files = server["file_system"].get(current_path, [])
            filename = parts[1]
            if filename in files:
                output_func(f"Скачиваем файл {filename}\n", 'system')
                time.sleep(3)
                output_func(f"Файл {filename} скачан\n", 'system')
                if filename == 'passwds.txt':
                    success(output_func, server_ref)
            else:
                output_func(f"Файл {filename} не найден.\n", "error")

        if command == 'delete':
            if len(parts) < 2:
                output_func("Использование: delete <имя_файла>")
                return
            files = server["file_system"].get(current_path, [])
            filename = parts[1]
            if filename in files:
                output_func(f"Файл {filename} удалён")
                if filename == "server_script.txt":
                    success(output_func, server_ref)
            else:
                output_func(f"Файл {filename} не найден.\n", "error")

        output_func("Неизвестная команда. Введите help для списка.\n", "error")

    if ip == "192.168.1.193":
        if command == "back":
            if current_path == "/":
                output_func("Вы уже в корневом каталоге.\n", "system")
            else:
                parts = current_path.strip("/").split("/")
                parts.pop()  # убираем последний сегмент пути
                new_path = "/" + "/".join(parts) if parts else "/"
                server["current_path"] = new_path
                output_func(f"Вы вернулись в {new_path}\n", "system")
                return

        if command == "ls":
            files = server["file_system"].get(current_path, [])
            if not files:
                output_func("Содержимое: (пусто)\n", "system")
            else:
                output_func("Содержимое:\n" + "\n".join(f"  {f}" for f in files) + "\n", "system")
            return

        if command == "cd":
            if len(parts) < 2:
                output_func("Укажите папку. Пример: cd vault\n", "error")
                return
            target = parts[1]
            if not target.startswith("/"):
                target = current_path.rstrip("/") + "/" + target
            if target in server["locked_paths"]:
                output_func(f"Папка {target} заблокирована.\n", "error")
            elif target not in server["file_system"]:
                output_func(f"Папка {target} не найдена.\n", "error")
            else:
                server["current_path"] = target
                output_func(f"Вы перешли в {target}\n", "system")
            return
    
        if command == 'bruteforce':
            if len(parts) < 2:
                output_func("Укажите папку", 'error')
                return
            target = parts[1]
        # Приведём target к абсолютному пути, если нужно
            if not target.startswith('/'):
                target = server['current_path'].rstrip('/') + '/' + target

            if target not in server['locked_paths']:
                output_func("Папка не заблокирована.\n", 'system')
            else:
                opened = random.randint(1, 2)  # случайное 1 или 2
                if opened == 1:
                    # Успешно разблокируем — удаляем из locked_paths
                    server['locked_paths'].remove(target)
                    output_func('Папка разблокирована!\n', 'system')
                else:
                    output_func('Попытка bruteforce неудачна.\n', 'system')
            return

        if command == "cat":
            if len(parts) < 2:
                output_func("Использование: cat <имя_файла>\n", "error")
                return
            filename = parts[1]
            files = server["file_system"].get(current_path, [])
            if filename in files:
                full_path = current_path.rstrip("/") + "/" + filename
                content = server["files_content"].get(full_path, "(пустой файл)\n")
                output_func(f"{content}\n", "system")
            else:
                output_func(f"Файл {filename} не найден.\n", "error")
            return
        
        if command == "download":
            if len(parts) < 2:
                output_func("Использование: download <имя_файла>\n", "error")
                return
            files = server["file_system"].get(current_path, [])
            filename = parts[1]
            if filename in files:
                output_func(f"Скачиваем файл {filename}\n", 'system')
                time.sleep(3)
                output_func(f"Файл {filename} скачан\n", 'system')
            else:
                output_func(f"Файл {filename} не найден.\n", "error")

        output_func("Неизвестная команда. Введите help для списка.\n", "error")