from common.container import Container
from common.errors import KareErrors as RError
from common.log import Log 
import dbus
import os
import sys
import re
from dbus.types import UnixFd
import random

class Run(Container, RError):

    def __init__(self, args, token=None, redirect_io=False):
        self.package = args[0]
        self.chroot = False
        if self.package == "dkmsContainer":
            self.chroot=True
            if os.getuid() != 0:
                print("错误:运行dkms命令需要 root 权限")
                sys.exit(1)
        self.config = self.INSTALL_JSON
        self.log = Log("/var/log/kare/kare-run.log")
        self.conf = None
        self.path = None
        self.args = [re.escape(s) for s in args[1:]]
        self.desktop_path = ''
        self.iface = None
        self.exec = None
        self.base_env = None
        self.is_upgrade = False
        self.token = token
        self.terminal = False
        self.redirect_io = redirect_io
        self.crun_config = None
        if self.redirect_io:
            self.crun_config = "config{}.json".format(random.randint(1, 10000))
        self.pre_run()
        Container.__init__(self, self.is_shadow(self.base_env), self.log, self.chroot)
        self.build_run_cmd()
        self.run()

    """
    @brief 处理运行前逻辑， 检测包是否存在等，检测生效容器，代理程序启动 相关逻辑
    """
    def pre_run(self):
        self.conf = self.get_config_json(self.INSTALL_JSON, self.package)
        if self.conf is None:
            self.log.error(self.PACKAGE_NOT_INSTALL[1].format(self.package))
            raise RuntimeError(self.PACKAGE_NOT_INSTALL)
        self.base_env = self.conf.get("base_env")
        self.release_path = self.get_release_path(self.base_env)
        self.path = self.conf.get("path")
        self.is_upgrade = self.conf.get("upgrade", False)
        desktop_files = [file for file in self.conf.get("file") if file.endswith(".desktop")]
        self.log.info("桌面文件：{}".format(desktop_files))
        for desktop_file in desktop_files:
            exec_file=None
            term_val=None
            exec_val=[]
            if os.path.exists(desktop_file):
               with open(desktop_file, 'r', encoding='utf-8', errors='ignore') as f:
                for line in f:
                    if line.startswith("Exec="):
                        exec_file = line.split("=")[1].strip()
                    if line.startswith("Terminal="):
                        term_val = line.split("=")[1].strip()
                    if line.startswith("#Path="):
                        self.desktop_path = 'cd ' + line.split('=')[1].strip() + '; '
            self.log.info("exec_file:{}".format(exec_file))
            if os.path.exists(exec_file):
                with open(exec_file) as f:
                    for l in f:
                        if l.startswith("/usr/bin/kare run"):
                            exec_val = l.split()[3:-1]
            arglist =  [re.sub(r'\\', '', s) for s in self.args]
            # self.log.info("arglist:{}".format(arglist))
            # self.log.info("exec_val:{}".format(exec_val))
            if exec_val == arglist and term_val == "true":
                self.terminal = True
            else:
                arglist[0] = "/opt/kare/usr/bin/" + arglist[0]
                if exec_val == arglist and term_val == "true":
                    self.terminal = True 
        self.log.info("terminal:{}".format(self.terminal))
        

    """
    @brief 通过普通用户执行相关操作，构建config.json文件
    """        
    def build_run_cmd(self):
        if not self.terminal:
            cmd = '''{}/usr/bin/tini -s -g -n -- {}'''.format(self.desktop_path, " ".join(map(lambda x: f"''" if x == '' else x, self.args)))
        else:
            cmd = '''{}/usr/bin/tini -s -g -n -- mate-terminal --disable-factory -e {}'''.format(self.desktop_path, " ".join(map(lambda x: f"''" if x == '' else x, self.args)))
        if self.package == "dkmsContainer":
            cmd = ' '.join(self.args)
            self.exec = self.container.exec(self.path + "/merge", cmd)
        else:
            if self.is_upgrade:
                self.exec = self.container.exec(self.path, 
                                                crun_cmd=cmd, 
                                                release=self.base_env)
                return
            self.exec = self.container.exec(self.path + "/merge", 
                                            crun_cmd=cmd, 
                                            release=self.base_env,
                                            white_container_name=self.package, crun_config=self.crun_config)

    def _call_dbus(self):
        bus = dbus.SystemBus()
        kare_bus = bus.get_object('com.kylin.kareAgent', '/com/kylin/kareAgent')
        self.iface = dbus.Interface(kare_bus, 'com.kylin.kareAgent')

    def run(self):
        self._call_dbus()
        if self.is_upgrade is False:
            self.iface.mount_overlay(self.get_base_dirs(self.release_path), self.path)
        if self.package == "dkmsContainer":
            self.mount_overlay(self.get_base_dirs(self.release_path), self.path)
            self.log.info(f'dkms运行命令:{self.exec}')
            self.container.mount_share_dirs(self.package)
            try:
                ret = self.run_command_status_output(self.exec)
                self.log.info(f'dkms运行结果:{ret}')
            except Exception as e:
                self.log.error(f"Failed to run dkmsContainer:{e}")
            self.container.umount_share_dirs(self.package)
            sys.exit(ret[0])
        if self.token:
            self.iface.run_command_line(self.exec, self.package, self.token)
        elif self.redirect_io:
            stdin_fd = UnixFd(os.dup(sys.stdin.fileno()))
            stdout_fd = UnixFd(os.dup(sys.stdout.fileno()))
            stderr_fd = UnixFd(os.dup(sys.stderr.fileno()))
            back_fd = UnixFd(os.dup(3))
            side_fd = UnixFd(os.dup(4))
            self.iface.run_cups_filter(self.exec, self.package, stdin_fd, stdout_fd, stderr_fd, back_fd, side_fd)
        else:
            self.iface.run(self.exec, self.package)
    
