from common.utils import HostMessage, RequireRoot, GlobalSingleton
from buildenv.release import *
from common.log import Log


@RequireRoot
class BuildEnv(HostMessage, BaseRelease, GlobalSingleton):
    LOCK_FILE = "/var/lock/kare-build.lock"
    flag = False

    def __init__(self, env: str, chroot=False):
        GlobalSingleton.__init__(self)
        BaseRelease.__init__(self, env)
        self.env = env
        self.chroot = chroot
        self.path = self.get_save_path("kare-" + self.env)
        self.log = Log("/var/log/kare/kare-build.log")
        self.mirrors = self.release.get_build_mirrors
        if self.mirrors is None:
            self.release.build(self.path)
            self.set_config_json(self.RELEASE_JSON, self.env, self.path)
            exit()
        self.user_config=["passwd", "shadow", "group", "gshadow", "subgid", "subuid", "passwd-", "shadow-", "group-", "gshadow-", "subgid-", "subuid-", "uid_list", "timezone", "localtime", "locale.gen"]

        self.scripts = ["agent.py", "fix_depends.py", "kare-apt.py", "kare-hook.py"]

        ret = self.pre_build() 
        if ret:
            exit(ret)
        ret = self.build()
        if ret:
            exit(ret)
        self.updata_config()

    """
    @brief 构建前的检测，包括网络环境、权限、存储空间等检测
    """    
    def pre_build(self):
        if self.avaliable_space("/data" if self.path.startswith("/data") else "/") is False:
            self.log.error("存储空间不足")
            raise RuntimeError(self.INSUFFICIENT_SPACE)

        if self.get_release_path(self.env):
            self.log.error("基础环境已存在")
            raise RuntimeError(self.ALREADY_EXISTS)

        if self.check_website_port_connectivity(self.mirrors) is False:
            self.log.error("网络连接失败")
            raise RuntimeError(self.NETWORK_ERROR)

    """
    @brief debootstrap构建环境
    """    
    def build(self):
        arch = self.get_build_arch()
        if arch is None:
            self.log.error("不支持的架构")
            raise RuntimeError(self.UNSUPPORTED_ARCH)
        include_list = self.release.get_build_includes
        if arch == "loongarch64" and self.env == "v10sp1":
            include_list.remove("gcc-10-base")
            include_list.remove("gcc-9-base")
            include_list.remove("libgcc-s1")
            include_list.append("libsodium23")
            include_list.append("libcurl4")
            include_list.append("libaudio2")
            include_list.append("libminizip1")
            include_list.append("libxslt1.1")
            include_list.append("libwebpdemux2")
            include_list.append("libglu1-mesa")
            include_list.append("libqt5opengl5")
            include_list.append("libxcb-damage0")
            include_list.append("libxcb-composite0")
            include_list.append("libxklavier16")

        include = ",".join(include_list)
        components = self.release.get_build_components
        suite = self.release.get_build_suite
        cmd = "/usr/sbin/debootstrap --verbose --no-merged-usr --variant=minbase --arch={} --include={} --components={} {} {} {}".format(arch, include, components, suite, self.path, self.mirrors)
        if self.chroot == False:
            if self.run_command_realtime(cmd, self.log) !=0:
                self.log.error("构建失败")
                raise RuntimeError(self.BUILD_INSTALL_ERROR)
        else:
            if self.run_command_status(cmd) !=0:
                self.log.error("构建失败")
                raise RuntimeError(self.BUILD_INSTALL_ERROR)
    """
    @brief 基础环境构建完成后，补充配置， 包括用户信息，源，依赖，系统配置文件更新等操作
    """    
    def updata_config(self):
        for config in self.user_config:
            try:
                self.copy_file("/etc/" + config, self.path + "/etc/" + config)
            except OSError as e:
                self.log.error(f"拷贝配置文件失败: {e}")
            except PermissionError as e:
                self.log.error(f"权限不足: {e}")

        # 容器内脚本下载

        # 容器内apt相关脚本下载
        for script in self.scripts:
            self.copy_file(self.CONTAINER_PATH + "/" + script, self.path + "/usr/bin/")

        # 容器内代理相关脚本拷贝
        self.copy_file(self.PLUGIN_PATH + "/host-agent/host-spawn", self.path + "/usr/bin/")
        self.copy_file(self.PLUGIN_PATH + "/bus/dbus-daemon-proxy", self.path + "/usr/bin/")
        self.copy_file(self.PLUGIN_PATH + "/host-agent/hostAgent", self.path + "/usr/bin/")
        self.copy_file(self.PLUGIN_PATH + "/tini/tini", self.path + "/usr/bin/")

        soure_list = self.path + "/etc/apt/sources.list"
        for extra_mirror in self.release.get_extra_mirrors:
            self.run_command("echo '" + extra_mirror + "' >>" + soure_list)
        try:
           result = self.ksaf_set_label_for_kare_interpreter(self.path)
           if result == 0:
               self.log.info("kare基础环境安装时脚本解释器标记设置成功")
           elif result == -1:
               self.log.error("kare基础环境安装时脚本解释器标记设置失败,参数错误")
           else:
               self.log.error("kare基础环境安装时脚本解释器标记设置失败")
        except Exception as e:
            self.log.error(f"kare基础环境安装时脚本解释器标记设置失败,未知错误:{e}")
        apt_update = "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'apt update'\"".format(self.path)
        self.run_command(apt_update)
        apt_file_update = "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'apt-file update'\"".format(self.path)
        self.run_command(apt_file_update)
        apt_fix =  "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'apt install -f -y'\"".format(self.path)
        self.run_command(apt_fix)
    
        if self.release.get_extra_includes:
            extra_include =  "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'mount -t proc proc /proc;DEBIAN_FRONTEND=noninteractive apt install {} -y '\"".format(self.path, self.release.get_extra_includes)
            self.log.info(self.run_command(extra_include))
        locale_gen = "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'umount /proc;locale-gen'\"".format(self.path)
        self.run_command(locale_gen)
        if self.env == "v10sp1":
            arch_name = self.run_command("uname -m")
            self.run_command("cp /usr/share/kare/plugins/libgtk-3-0/*.so* {}/usr/lib/{}-linux-gnu/".format(self.path, arch_name))
            self.run_command("mkdir -p {}/tmp/cups/".format(self.path))
            self.run_command("cp /usr/share/kare/plugins/cups/*.deb {}/tmp/cups/".format(self.path))
            dpkg_cups =  "unshare --pid --mount --uts --ipc --fork --mount-proc /bin/bash -c \"/usr/sbin/chroot {} /bin/bash -c 'DEBIAN_FRONTEND=noninteractive dpkg -i /tmp/cups/*.deb'\"".format(self.path)
            self.run_command(dpkg_cups)
        self.set_config_json(self.RELEASE_JSON, self.env, self.path)
        self.run_command(f"rm -rf {self.path}/var/cache/apt/archives/*.deb")
        self.log.info("Build Success")
