import subprocess
import re
import sys
import subprocess
import os
import threading
import json

class ContainerMessage():

    @property
    def get_release(self):
        return subprocess.getoutput("cat /etc/lsb-release | grep DISTRIB_DESCRIPTION | awk -F '=' '{print $2}'").strip("\"")

    def get_config_json(self, key=None):
        try:
            with open("/etc/kare/whitelist/kare-apt", 'r') as file:
                data = json.load(file)
            if key is not None:
                return data.get(key, None)
            else:
                return data
        except json.decoder.JSONDecodeError:
            return None
        except FileNotFoundError:
            return None

class KareApt(ContainerMessage):

    def __init__(self, deb):
        self.whitelist_package = self.get_config_json("whitelist")
        # TODO v10 v10-sp1 做区分
        self.RELEASE = self.get_release
        if self.RELEASE == "Kylin V10":
            self.blacklist = self.get_config_json("v10_blacklist")
        else:
            self.blacklist = self.get_config_json("blacklist")

        self.depends_version_dict = {}
        self.apt_list=[]
        self.v10_apt_list = self.get_config_json("v10_apt_list")
        self.sp1_apt_list = self.get_config_json("sp1_apt_list")
        self.v11_apt_list = self.get_config_json("v11_apt_list")
        self.deb = deb
        self.log = deb.rsplit("/")[-1] + "_log"
        
    def tail(self):
        os.system('touch /var/{}'.format(self.log))
        # os.system('tail /var/{}'.format(self.log))

    def lower_apt(self, target, version):
        for T in target.split("\n"):
            if T.strip().startswith("500"):
                continue
            else:
                now = T.strip().strip("*** ").split("500")[0].strip()
                ret = subprocess.getoutput("dpkg --compare-versions {} le {} && echo True".format(now, version.strip("<").strip("=")))
                if ret == "True":
                    return now
        else:
            return False

    def apt(self, deb):
        ret = subprocess.getoutput('DEBIAN_FRONTEND=noninteractive SYSTEMCTL_FORCE_BUS=1 SYSTEMD_IGNORE_CHROOT=1 apt-get -f install -y {} -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" | tee -a /var/{} '.format(deb, self.log))
        if "下列软件包有未满足的依赖关系：" in ret:
            for i in ret.split("下列软件包有未满足的依赖关系：")[-1].strip().split("\n")[0:-1]:
                if "依赖" in i:
                    depend = i.split("依赖: ")[-1].split(" ")[0].strip()
                    try:
                        version = re.findall(r'\((.*?)\)', i)[0]
                    except IndexError:
                        version = ">"
                    if version.startswith(">"):
                        self.apt(depend)
                    elif version.startswith("<"):
                        policy = subprocess.getoutput("apt-cache policy {} | grep 500".format(depend))
                        ver = self.lower_apt(policy, version)
                        if ver:
                            self.apt(depend+"="+ver)
                    else:
                        x = subprocess.getoutput("apt-cache policy {} | grep '{}'\ ".format(depend, version.split(" ")[-1])).rsplit("500", 1)[0].strip()
                        self.apt(depend+"="+x)
                elif "冲突" in i:
                    depend = i.split("冲突: ")[-1].split(" ")[0].strip()
                    try:
                        version = re.findall(r'\((.*?)\)', i)[0]
                    except IndexError:
                        version = ">"
                    if version.startswith(">"):
                        self.apt(depend)
                    elif version.startswith("<"):
                        policy = subprocess.getoutput("apt-cache policy {} | grep 500".format(depend))
                        ver = self.lower_apt(policy, version)
                        if ver:
                            self.apt(depend+"="+ver)
                    else:
                        x = subprocess.getoutput("apt-cache policy {} | grep '{}'\ ".format(depend, version.split(" ")[-1])).rsplit("500", 1)[0].strip()
                        self.apt(depend+"="+x)
            os.system('DEBIAN_FRONTEND=noninteractive apt-get -f install -y {} -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" '.format(deb))
        elif "在处理时有错误发生：" in ret or "无法找到文件 - " in ret and "错误:" in ret:
            sys.exit(80)

    def set_depend_version(self, depend, version):
        if depend.strip() in self.blacklist:
            return
        if version is None:
            policy = subprocess.getoutput("apt-cache policy {} | grep 500".format(depend))
            if policy:
                self.depends_version_dict.setdefault(depend, None)
            return
        if version.startswith(">"):
            policy = subprocess.getoutput("apt-cache policy {} | grep 500".format(depend))
            if policy:
                self.depends_version_dict.setdefault(depend, None)
            return
        elif version.startswith("<"):
            #TODO set version
            policy = subprocess.getoutput("apt-cache policy {} | grep 500".format(depend))
            ver = self.lower_apt(policy, version)
            if ver:
                self.depends_version_dict[depend] = ver
            return  
        else:
            x = subprocess.getoutput("apt-cache policy {} | grep '{}'".format(depend, version.split(" ")[-1])).rsplit("500", 1)[0].strip().split("\n")[-1].strip()
            self.depends_version_dict.setdefault(depend, x)
            return

    def get_deb_depends_version(self, debs):
        for i in debs:
            v = None
            pkg = i.strip()
            if "|" in pkg:
                pkgs = pkg.split("|")
                for p in pkgs:
                    version = None
                    if "(" in p:
                        p = p.split("(")[0].strip()
                        version = re.findall(r'\((.*?)\)', i)[0]
                    self.set_depend_version(p, version)
            elif "(" in pkg:
                pkg= pkg.split("(")[0].strip()
                version = re.findall(r'\((.*?)\)', i)[0]
                self.set_depend_version(pkg, version)
            else:
                self.set_depend_version(pkg, v)

    def build_apt(self):
        for depends in self.depends_version_dict:
            if self.depends_version_dict[depends] is None or self.depends_version_dict[depends] == "":
                self.apt_list.append(depends)
            else:
                 self.apt_list.append("{}={}".format(depends, self.depends_version_dict[depends]))
         

    def get_deb_depends(self):
        # 依赖包安装
        package = subprocess.getoutput("dpkg -I {} | grep Package".format(self.deb)).split(" Package:")[-1].strip()
        if package in self.v10_apt_list and self.RELEASE == "Kylin V10" or package in self.sp1_apt_list and self.RELEASE == "Kylin V10 SP1" or (self.RELEASE == "Kylin V11" or self.RELEASE.startswith("openKylin 2")):
            if self.RELEASE == "Kylin V11" or self.RELEASE.startswith("openKylin 2"):
                ret = os.system('SYSTEMCTL_FORCE_BUS=1 SYSTEMD_IGNORE_CHROOT=1 DEBIAN_FRONTEND=noninteractive apt-get -f install -y {} -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" '.format(self.deb))
            else:
                ret = os.system('DEBIAN_FRONTEND=noninteractive apt-get -f install -y {} -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" '.format(self.deb))
            if ret != 0:
                exit(-1)
            else:
                exit(0)
        if self.whitelist_package.get(package):
            self.apt(" ".join(self.whitelist_package.get(package)))
        debs = subprocess.getoutput("dpkg -I {} | grep Depends".format(self.deb)).split(" Depends:")[-1].split(",")
        self.get_deb_depends_version(debs)
        pre_debs = subprocess.getoutput("dpkg -I {} | grep Pre-Depends".format(self.deb)).split(" Pre-Depends:")[-1].split(",")
        self.get_deb_depends_version(pre_debs)
        self.build_apt()
        # os.system("apt-get install -s -y {}".format(" ".join(self.apt_list)))
        if package == "browser360-cn-stable" or package == "suwellreaderpro.appstore":
            os.system("rm -rf /usr/share/applications/defaults.list")
        self.apt(" ".join(self.apt_list))
        subprocess.getoutput("apt-get install -f -y")
        # 目标包安装
        # if self.RELEASE == "Kylin V11" or self.RELEASE.startswith("openKylin 2"):
        #     ret = os.system('SYSTEMD_IGNORE_CHROOT=1 DEBIAN_FRONTEND=noninteractive dpkg --force-confdef --force-confold -i {} '.format(self.deb))
        # else:
        #     ret = os.system('DEBIAN_FRONTEND=noninteractive dpkg --force-confdef --force-confold -i {} '.format(self.deb))
        ret = os.system('SYSTEMCTL_FORCE_BUS=1 SYSTEMD_IGNORE_CHROOT=1 DEBIAN_FRONTEND=noninteractive dpkg --force-confdef --force-confold -i {} '.format(self.deb))
        return ret

if __name__ == "__main__":
    kare = KareApt(sys.argv[1])
    p1 = threading.Thread(target=kare.tail, args=()) 
    p1.daemon = True
    p1.start()  
    ret = kare.get_deb_depends()
    if ret !=0:
        exit(11)

