from common.utils import PathManager, HostMessage
from common.log import Log
from install.resource import Resource, VpManager
from pathlib import Path
import os


class UpgradePackage(PathManager, HostMessage):

    def __init__(self, package_name, package_version, package_arch, log):
        self.package_name = package_name
        self.package_version = package_version
        self.package_arch = package_arch
        self.log = log

    """
    @brief 删除vp目录下所有文件
    """   
    def _clean_vp_path(self):
        self.log.info("清理vp目录下所有文件")
        self.remove_dir(os.path.dirname(self.VP_DEBIAN_PATH))

    def _ostree_dir_install(self, dir_path):
        if "DEBIAN" in dir_path.parts[5]:
            return
        p = (dir_path.parts[0], "opt", "kare",) + dir_path.parts[5:]
        ostree_dir_path = Path(*p)
        ostree_dir_path.mkdir(parents=True, exist_ok=True)

    def _ostree_file_install(self, file_path):
        if "DEBIAN" in file_path.parts[5]:
            return
        p = (file_path.parts[0], "opt", "kare",) + file_path.parts[5:]
        ostree_file_path = Path(*p)
        self.log.info(f"copy file {file_path} to {ostree_file_path}")
        self.copy_file(file_path, ostree_file_path)

    """
    @brief 不可变系统安装逻辑
    """   
    def _ostree_install(self):    
        vp_path = os.path.dirname(self.VP_DEBIAN_PATH)
        for root, dirs, files in os.walk(vp_path):
            # 跳过隐藏目录 (以 . 开头的目录)
            dirs[:] = [d for d in dirs if not d.startswith('.')]
            # 打印当前目录中的文件夹
            for d in dirs:
                self._ostree_dir_install(Path(os.path.join(root, d)))
                
            # 打印当前目录中的文件（跳过隐藏文件）
            for f in files:
                if not f.startswith('.'):
                    self._ostree_file_install(Path(os.path.join(root, f)))
        self._clean_vp_path()

    """
    @brief 安装虚包， 需要区分是否为不可变系统
    @return 
    """    
    def install(self)->bool:
        if self.is_ostree:
            self._ostree_install()
            return True
        ret = self.run_command_status(f"dpkg -i --force-overwrite {self.vp_package}")
        self._clean_vp_path()
        return True if ret == 0 else False

    """
    @brief 生成deb包
    @return 是否成功
    """   
    def pack(self)->bool:
        vp_path = os.path.dirname(self.VP_DEBIAN_PATH)
        deb_file = f"{os.path.dirname(vp_path)}/{self.package_name}_{self.package_version}-kare_{self.package_arch}.deb" 
        ret = self.run_command_status(" ".join(["dpkg-deb", "--build", vp_path, deb_file]))
        if ret == 0: 
            self.vp_package = deb_file
            self.log.info(f"生成deb包 {deb_file}成功")
            return True
        else:
            self.log.error(f"生成deb包 {deb_file}失败")
            return False

class Upgrade(HostMessage, PathManager):

    def __init__(self):
        self.log = Log("/var/log/kare/kare-upgrade.log")
        self.release_path, self.release = None, None
        self.build_upgrage_release()
        self.upgrade_file = self.release_path + self.UPGRADE_CONFIG_PATH
        self.compat_desktops = self.release_path + self.UPGRADE_COMPAT_DESKTOP_PATH
        self.read_upgrade_file()
        self.read_compat_desktops()
    
    """
    @brief  构建升级基础环境
    """
    def build_upgrage_release(self):
        release_base_path = "/ostree" if self.is_ostree else "/"
        for path in os.listdir(release_base_path):
            if path.startswith("krm-fsold-"):
                break
        else:
            raise Exception("No compatible layer found")
        self.release_path = os.path.join(release_base_path, path)
        self.release = path.replace("krm-fsold-", "upgrade-")
        with open(self.release_path + "/config.json", 'w') as f:
            f.close()
        os.chmod(self.release_path + "/config.json", 0o766)
        self.set_config_json(self.RELEASE_JSON, self.release, self.release_path)
        self.log.info("升级基础环境构建完成")

    """
    @brief 读取package-desktop.info文件, 获取包信息
    """
    def read_upgrade_file(self):
        self.log.info("处理资源文件{}".format(self.upgrade_file))
        with open (self.upgrade_file, "r") as f:
            for line in f.readlines():
                self._get_upgrade_package_info(line.strip())

    """
    @brief 获取用户桌面路径
    """
    def get_user_desktop_path(self):
        home = Path("/home")
        desktop_paths = []
        for user_dir in home.iterdir():
            if user_dir.is_dir():
                # 检查是否存在 Desktop 或 桌面 目录
                desktop_en = user_dir / "Desktop"
                desktop_cn = user_dir / "桌面"
                # 仅添加存在的路径
                if desktop_en.exists():
                    desktop_paths.append(str(desktop_en))
                if desktop_cn.exists():
                    desktop_paths.append(str(desktop_cn))
        return desktop_paths

    """
    @brief 读取compat-desktops文件, 获取桌面兼容desktop文件
    """
    def read_compat_desktops(self):
        user_desktop_path = self.get_user_desktop_path()
        base_path = "/opt/kare/" if self.is_ostree else "/"
        base_path += "usr/share/applications/"
        #TODO 拷贝文件至桌面
        self.log.info("处理桌面兼容desktop文件{}".format(self.upgrade_file))
        with open (self.compat_desktops, "r") as f:
            for line in f.readlines():
                self.copy_desktop_to_home(base_path + line.strip(), user_desktop_path)

    def copy_desktop_to_home(self, desktop, home_desktops):
        for path in home_desktops:
            self.copy_file(desktop, path)
            os.chmod(path + "/" +desktop.split("/")[-1], 0o777)
    
    """
    @brief 处理desktop分解，区分applications目录与 autostart目录
    """
    def _update_desktops_path(self, desktops, autodesktop):
        files = []
        for desktop in desktops.split(" "):
            files.append("/usr/share/applications/" + desktop.strip().strip(";"))
        if len(autodesktop) == 0:
            return files
        for auto in autodesktop.split(" "):
            files.append("/etc/xdg/autostart/" + auto.strip().strip(";"))
        return files

    """
    @brief 更新container_file列表
    """
    def _upaate_container_file_list(self, name):
        package_list = f"{self.release_path}{self.DPKG_INFO}{name}.list"
        if os.path.exists(package_list) is False:
            return []
        with open(package_list, "r") as f:
            container_files = [self.release_path + file_path.strip() for file_path in f.readlines() if file_path != "/.\n"]
            f.close()
        return container_files

    """
    @brief 拷贝资源文件致tmp目录
    """
    def copy_tmp_resource(self, name, container_files):
        icons = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".bmp", ".tiff", ".tif", ".webp", ".xpm", ".ico"]
        tmp_icons = []
        tmp_desktops = []
        for files in container_files:
            ext = os.path.splitext(files)[1].lower()
            if ext in icons:
                target = f"/tmp/{name}/" + files.split("/", 3 if self.is_ostree else 2)[-1]
                tmp_icons.append(target)
                self.copy_file(files, target)
            elif ext == ".desktop":
                target = f"/tmp/{name}/" + files.split("/", 3 if self.is_ostree else 2)[-1]
                tmp_desktops.append(target)
                self.copy_file(files, target)
        return tmp_desktops, tmp_icons

    def _get_upgrade_package_info(self, info):
        package_info, desktops_info = info.split(": ")
        name, version, arch = package_info.split("_", 2)
        desktops, autodesktop = desktops_info.strip().split(";")[0:2]
        desktop_files = self._update_desktops_path(desktops, autodesktop)
        # 处理包详细文件
        container_files = self._upaate_container_file_list(name)
        
        tmp_desktop, tmp_icon = self.copy_tmp_resource(name, container_files)

        r = Resource(self.log)
        r.edit_vp_desktop_file(name, tmp_desktop)
        # 虚包生成处理逻辑, Exec字段处理，安装
        p = UpgradePackage(name, version, arch, self.log)
        [self.kare_vp_cp(Path(desktop), False, index=3,log=self.log) for desktop in tmp_desktop]
        [self.kare_vp_cp(Path(icon), False,index=3,log=self.log) for icon in tmp_icon]
        files = self._update_list_files(os.path.dirname(self.VP_DEBIAN_PATH))
        vp = VpManager(p, files)

        package_conf = {
            "version": version,
            "upgrade": True,
            "base_env": self.release,
            "path": self.release_path,
            "driver": False,
            "file": files,
            "container_file": container_files,
            "desktop_files": desktop_files
        }

        self.set_config_json(self.INSTALL_JSON, name, package_conf)
        self.remove_dir(f"/tmp/{name}")
        self.log.info(f"删除/tmp/{name} 完成")
        
        del p, vp, r

    def _update_list_files(self, package_path):
        file = []
        package_path = os.path.abspath(package_path)
        base_path = "/opt/kare/" if self.is_ostree else "/"
        for root, dirs, files in os.walk(package_path):
            rel_path = os.path.relpath(root, package_path)
            if rel_path == '.':
                rel_path = ''
            for f in files:
                file_entry = os.path.join(rel_path, f) if rel_path else f
                file.append(f"{base_path}{file_entry}")
        return file
    

if __name__ == "__main__":
    upgrade = Upgrade()