import os.path
from pathlib import Path
import re

import javaproperties
import requests
from lxml import etree

from scripts.context import Context
from scripts.task import Task
from utils import FileUtils
from utils.logger_utils import app_logger


def update_dependency_version(content, dependency_name, new_version):
    """
    更新 Gradle 依赖的版本号

    :param content: Gradle 文件内容
    :param dependency_name: 依赖名称（可以是完整字符串或部分匹配）
    :param new_version: 新版本号
    :return: 更新后的内容
    """
    # 匹配 implementation 声明，捕获组用于保留前缀和后缀
    pattern = rf"(implementation\s*\(\s*['\"]{re.escape(dependency_name)}:)([^'\"]+)(['\"]\s*\))"

    # 替换版本号部分
    updated_content = re.sub(pattern, rf"\g<1>{new_version}\g<3>", content)

    return updated_content


def get_latest_version(url):
    try:
        response = requests.get(url)
        root = etree.fromstring(response.content)
        latest = root.xpath("//latest/text()") or root.xpath("//version[last()]/text()")
        return latest[0] if latest else None
    except Exception as e:
        app_logger().error(f"Error: {e}")
        return None


def uncomment_line(content, line_pattern):
    """
    取消指定行的注释

    :param content: 文件内容
    :param line_pattern: 要取消注释的行内容（不含前导//和空格）
    :return: 更新后的内容
    """
    # 匹配以//开头，后跟任意空格，然后是目标行内容
    pattern = rf'^(\s*)//\s*({re.escape(line_pattern)}\s*)$'

    # 替换为去注释版本（保留原有缩进）
    replacement = rf'\1\2'

    updated_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
    return updated_content


def update_gradle_variable(content, variable_name, new_value):
    """
    更新 Gradle 文件中的 final def 变量值

    :param content: Gradle 文件内容
    :param variable_name: 变量名 (如 "releaseName")
    :param new_value: 新值 (字符串或数字)
    :return: 更新后的内容
    """
    # 处理字符串值（带引号）
    if isinstance(new_value, str):
        # 匹配带引号的字符串赋值
        pattern = rf'(final\s+def\s+{re.escape(variable_name)}\s*=\s*["\'])(.*?)(["\'])'
        replacement = rf'\g<1>{new_value}\g<3>'
    else:
        # 匹配数字值（不带引号）
        pattern = rf'(final\s+def\s+{re.escape(variable_name)}\s*=\s*)(\d+)'
        replacement = rf'\g<1>{new_value}'

    updated_content = re.sub(pattern, replacement, content)
    return updated_content


def update_gradle_property(content, key, new_value):
    # 匹配两种格式：
    # 1. resValue "string", "key", "value"
    # 2. resValue("string", "key", "value")
    pattern = rf'(resValue\s*\(?\s*["\']string["\']\s*,\s*["\']{re.escape(key)}["\']\s*,\s*["\'])(.*?)(["\']\s*\)?)'

    # 替换为新值
    updated_content = re.sub(pattern, rf'\g<1>{new_value}\g<3>', content)

    return updated_content


GAME_ACTIVITY_PATH = f"LauncherCode/src/com/launchercode/GameActivity.kt".replace("/", os.sep)
ANDROID_MANIFEST_PATH = f"lawnchair/AndroidManifest.xml".replace("/", os.sep)


class ProjectUpdate(Task):

    def __init__(self, context: Context):
        super().__init__(context)
        self.build_gradle_path = None

    def update_package_name(self):
        """
        更新包名
        :return:
        """

        build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle")
        text = open(build_gradle_path, "r", encoding="utf-8").read()

        text = text.replace("com.fingerheart.launcher.game.free.sdjws", self.context.package_name)
        open(build_gradle_path, "w", encoding="utf-8").write(text)

        xml_path = os.path.join(self.context.temp_project_path, "lawnchair/res/xml")

        # com.launchercode.SplashActivity
        # TODO 这里还需要改启动项
        for root, dirs, files in os.walk(xml_path):
            for file in files:
                temp_xml_path = os.path.join(root, file)
                text = open(temp_xml_path, "r", encoding="utf-8").read()
                text = text.replace("com.fingerheart.launcher.game.free.sdjws", self.context.package_name)
                open(temp_xml_path, "w", encoding="utf-8").write(text)
                pass
        pass

    def update_keystore(self):
        root_dir = os.path.join("game_config", self.context.package_name)
        for file in os.listdir(root_dir):
            if file.endswith(".keystore"):
                name = file.replace(".keystore", "")
                FileUtils.copy(os.path.join(root_dir, file), os.path.join(self.context.temp_project_path, file))

                open(os.path.join(self.context.temp_project_path, "keystore.properties"), "w", encoding="utf-8").write(
                    f"""
keyAlias={name}
keyPassword=123456
storeFile=./{name}.keystore
storePassword=123456
"""
                )
                return

        raise Exception("keystore not found")

    def update_config(self):
        """
        更新配置文件
        :return:
        """
        root_dir = os.path.join("game_config", self.context.package_name)
        config_path = list(
            filter(lambda f: f.endswith(".zip") and f.startswith(self.context.package_name), os.listdir(root_dir)))
        if len(config_path) <= 0:
            raise Exception("config not found")

        target_path = os.path.join(root_dir, config_path[0])

        dst = os.path.join(self.context.temp_project_path, config_path[0].replace(".zip", ""))

        result = FileUtils.decompress(target_path, dst)
        app_logger().debug(f"{target_path} -> {dst} , 解压结果: {result}")

        mainly_path = os.path.join(dst, "mainly")

        google_services_json_path = os.path.join(dst, "google-services.json")

        FileUtils.copy(google_services_json_path,
                       os.path.join(self.context.temp_project_path, "google-services.json"),
                       True)

        dst_path = os.path.join(self.context.temp_project_path, f"lawnchair{os.sep}assets")

        for file in list(filter(lambda f: f != "google_fonts.json", os.listdir(dst_path))):
            FileUtils.delete(os.path.join(dst_path, file), True)
            pass

        for file in list(filter(lambda f: f.find(".") <= 0, os.listdir(mainly_path))):
            FileUtils.copy(os.path.join(mainly_path, file), os.path.join(dst_path, file))

        with open(os.path.join(mainly_path, "tkg_config_mainly.properties"), 'rb') as f:
            self.context.config = javaproperties.load(f)

        if self.context.admob_app_id is None or self.context.admob_app_id == "":
            self.context.admob_app_id = self.context.get_config("admob_id")
        pass

    def update_icon(self):
        """
        更新游戏Icon
        :return:
        """

        target_icon_path = os.path.join("game_config", self.context.package_name, "icon.zip")
        tag = "res_icon_resources"
        dst = os.path.join(self.context.temp_project_path, tag)
        FileUtils.decompress(target_icon_path, dst)

        for root, dirs, files in os.walk(dst):
            for file in files:
                temp_tart_path = os.path.join(root, file)
                if temp_tart_path.find("__MACOSX") > 0:
                    continue
                temp_dst = temp_tart_path.replace(tag, "res")
                app_logger().debug(f"copy icon = {temp_tart_path} -> {temp_dst}")
                FileUtils.copy(temp_tart_path, temp_dst, True)
        pass

    def update_game_result(self):
        """
        更新游戏资源
        :return:
        """
        root_dir = os.path.join("game_config", self.context.package_name)

        if self.context.game_type == "unity_native":
            res_path = os.path.join(root_dir, "unityLibrary.zip")
            if not os.path.exists(res_path):
                raise Exception("unity library not found")
            dst = os.path.join(self.context.temp_project_path, "unityLibrary")
            temp_dst = dst + "_res"
            if os.path.exists(dst):
                FileUtils.delete(dst, True)
            FileUtils.decompress(res_path, temp_dst)

            if os.listdir(temp_dst).index("unityLibrary") >= 0:
                FileUtils.copy(os.path.join(temp_dst, "unityLibrary"), dst)
            else:
                FileUtils.copy(temp_dst, dst)

            text = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").read()
            text = text.replace("implementation", "api")
            open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").write(text)

            # 引用Unity项目
            text = open(self.build_gradle_path, "r", encoding="utf-8").read()
            text = uncomment_line(text, "implementation projects.unityLibrary")
            open(self.build_gradle_path, "w", encoding="utf-8").write(text)

            # launcher 引用 unityActivity

            text = open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "r", encoding="utf-8").read()
            text = text.replace("WebActivity", "com.unity3d.player.UnityPlayerActivity")
            open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "w", encoding="utf-8").write(text)

            text = open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "r",
                        encoding="utf-8").read()
            # text = text.replace("WebActivity", "com.unity3d.player.UnityPlayerActivity")
            open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "w", encoding="utf-8").write(text)



        else:
            raise Exception(f"不支持的游戏类型 : {self.context.game_type}")
        pass

    def update_image(self):
        """
        更新游戏的资源
        :return:
        """
        root_dir = os.path.join("game_config", self.context.package_name)
        drawable_path = os.path.join(root_dir, "drawable-xxhdpi.zip")
        if not os.path.exists(drawable_path):
            raise Exception("drawable not found")
        dst = os.path.join(self.context.temp_project_path, "drawable_res")
        FileUtils.decompress(drawable_path, dst)

        if os.path.join(dst, "drawable-xxhdpi"):
            dst = os.path.join(dst, "drawable-xxhdpi")

        target_root_path = os.path.join(self.context.temp_project_path,
                                        f"LauncherCode{os.sep}res{os.sep}drawable-xxhdpi")

        image_list = list(map(lambda f: Path(f).stem, os.listdir(target_root_path)))

        for file in os.listdir(dst):
            temp_tar = os.path.join(dst, file)
            temp_dst = os.path.join(target_root_path, file)
            file_name = Path(file).stem
            if file_name in image_list:
                FileUtils.delete(os.path.join(target_root_path, file_name + ".png"))
                FileUtils.delete(os.path.join(target_root_path, file_name + ".jpg"))
                pass
            FileUtils.copy(temp_tar, temp_dst, True)
            pass

    def update_gradle_config(self):
        """
        更新gradle里面的版本号
        :return:
        """

        build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle")

        text = open(build_gradle_path, "r", encoding="UTF-8").read()

        text = update_gradle_property(text, "admob_app_id", self.context.admob_app_id)
        text = update_gradle_property(text, "game_services_project_id", self.context.game_services_project_id)
        text = update_gradle_property(text, "facebook_app_id", self.context.facebook_app_id)
        text = update_gradle_property(text, "facebook_client_token", self.context.facebook_client_token)
        text = update_gradle_property(text, "derived_app_name", self.context.get_app_name())
        text = update_gradle_variable(text, "versionDisplayName", self.context.version_display_name)
        text = update_gradle_variable(text, "version_code", self.context.version_code)
        text = update_dependency_version(text, f"straw:hachisdk_unity_{self.context.package_name}",
                                         self.context.sdk_prolink_version)
        text = update_dependency_version(text, f"com.game:hachisdk_unity_{self.context.package_name}",
                                         self.context.sdk_version)
        open(build_gradle_path, "w", encoding="UTF-8").write(text)
        pass

    def execute(self):
        self.build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle")
        self.init_sdk_version()
        self.update_package_name()
        self.update_keystore()
        self.update_config()
        self.update_icon()
        self.update_image()
        self.update_game_result()
        self.update_gradle_config()
        pass

    def get_sdk_version(self) -> str:
        for i in range(3):
            try:
                url = f"https://repo.dgtverse.cn/repository/tk_my/com/game/hachisdk_unity_{self.context.package_name}/maven-metadata.xml"
                version = get_latest_version(url)
                if version:
                    return version
                pass
            except Exception as e:
                pass
        raise Exception("sdk error.")

    def get_prolink_version(self) -> str:
        for i in range(3):
            try:
                url = f"https://repo.dgtverse.cn/repository/tk_my/straw/hachisdk_unity_{self.context.package_name}/maven-metadata.xml"
                version = get_latest_version(url)
                if version:
                    return version
            except Exception as e:
                pass
        raise Exception("sdk prolink error.")

    def init_sdk_version(self):
        self.context.sdk_version = self.get_sdk_version()
        self.context.sdk_prolink_version = self.get_prolink_version()
        pass
