import os
import sys
import json
import requests
import colorama
import importlib
import subprocess
from tqdm import tqdm

def init() -> dict:
    for directory in ["original", "modified", "patches", "tools", "decompiled"]:
        if not os.path.exists(directory):
            os.makedirs(directory)

    with open("./patches/config.json", "r") as config_file:
        conf = json.load(config_file)

    if not os.path.exists("./tools/apktool.jar"):
        try:
            print("Скачивание Apktool...")
            jar_response = requests.get(conf["tools"]["apktool_jar_url"], stream=True)
            jar_path = "tools/apktool.jar"
            with open(jar_path, "wb") as f:
                for chunk in jar_response.iter_content(chunk_size=8192):
                    f.write(chunk)

            wrapper_response = requests.get(conf["tools"]["apktool_wrapper_url"])
            wrapper_path = "tools/apktool"
            with open(wrapper_path, "w") as f:
                f.write(wrapper_response.text)
            os.chmod(wrapper_path, 0o755)

        except Exception as e:
            print(f"Ошибка при скачивании Apktool: {e}")
            exit(1)

    try:
        result = subprocess.run(
            ["java", "-version"], capture_output=True, text=True, check=True
        )

        version_line = result.stderr.splitlines()[0]
        if "1.8" in version_line or any(f"{i}." in version_line for i in range(9, 100)):
            print("Java 8 или более поздняя версия установлена.")
        else:
            print("Java 8 или более поздняя версия не установлена.")
            sys.exit(1)
    except subprocess.CalledProcessError:
        print("Java не установлена. Установите Java 8 или более позднюю версию.")
        exit(1)

    return conf

def select_apk() -> str:
    apks = []
    for file in os.listdir("original"):
        if file.endswith(".apk") and os.path.isfile(os.path.join("original", file)):
            apks.append(file)

    if not apks:
        print("Нет файлов .apk в текущей директории")
        sys.exit(1)

    while True:
        print("Выберете файл для модификации")
        for index, apk in enumerate(apks):
            print(f"{index + 1}. {apk}")
        print("0. Exit")

        try:
            selected_index = int(input("\nВведите номер файла: "))
            if selected_index == 0:
                sys.exit(0)
            elif selected_index > len(apks):
                print("Неверный номер файла")
            else:
                apk = apks[selected_index - 1]
                print(f"Выбран файл {apk}")
                return apk
        except ValueError:
            print("Неверный формат ввода")
        except KeyboardInterrupt:
            print("Прервано пользователем")
            sys.exit(0)


def decompile_apk(apk: str):
    print("Декомпилируем apk...")
    try:
        result = subprocess.run(
            "tools/apktool d -f -o decompiled " + os.path.join("original", apk),
            shell=True,
            check=True,
            text=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE,
        )
    except subprocess.CalledProcessError as e:
        print("Ошибка при выполнении команды:")
        print(e.stderr)
        sys.exit(1)


class Patch:
    def __init__(self, name, pkg):
        self.name = name
        self.package = pkg
        self.applied = False
        try:
            self.priority = pkg.priority
        except AttributeError:
            self.priority = 0

    def apply(self, conf: dict) -> bool:
        try:
            self.applied = self.package.apply(conf)
            return True
        except Exception as e:
            print(f"Ошибка при применении патча {self.name}: {e}")
            print(e.args)
            return False


conf = init()
apk = select_apk()
patch = decompile_apk(apk)

patches = []
for filename in os.listdir("patches/"):
    if filename.endswith(".py") and filename != "__init__.py":
        module_name = filename[:-3]
        module = importlib.import_module(f"patches.{module_name}")
        patches.append(Patch(module_name, module))

patches.sort(key=lambda x: x.package.priority, reverse=True)

for patch in tqdm(patches, colour="green", desc="Применение патчей"):
    tqdm.write(f"Применение патча: {patch.name}")
    patch.apply(conf)

statuses = {}
for patch in patches:
    statuses[patch.name] = patch.applied
    marker = colorama.Fore.GREEN + "✔" if patch.applied else colorama.Fore.RED + "✘"
    print(f"{marker}{colorama.Style.RESET_ALL} {patch.name}")

if all(statuses.values()):
    print("Все патчи успешно применены")
elif any(statuses.values()):
    print("Некоторые патчи не были успешно применены")
else:
    print("Ни один патч не был успешно применен")
