import configparser
import glob
import os
import shutil
import zipfile
import hashlib
from tools.helper import download_file, get_download_dir, host
from tools import container
from tools.logger import Logger


class General:
    files = []

    @property
    def arch(self):
        return host()

    @property
    def skip_extract(self):
        return False

    @property
    def download_loc(self):
        return os.path.join(get_download_dir(), self.dl_file_name)

    @property
    def copy_dir(self):
        if container.use_overlayfs():
            return "/var/lib/waydroid/overlay"
        else:
            return "/tmp/waydroid"

    def download(self):
        Logger.info("Downloading {} now to {} .....".format(
            self.dl_file_name, self.download_loc))
        loc_md5 = ""
        if os.path.isfile(self.download_loc):
            with open(self.download_loc, "rb") as f:
                bytes = f.read()
                loc_md5 = hashlib.md5(bytes).hexdigest()
        while not os.path.isfile(self.download_loc) or loc_md5 != self.act_md5:
            if os.path.isfile(self.download_loc):
                os.remove(self.download_loc)
                Logger.warning(
                    "md5 mismatches, redownloading now ....")
            loc_md5 = download_file(self.dl_link, self.download_loc)

    def remove(self):
        for f in self.files:
            file = os.path.join(self.copy_dir, self.partition, f)
            if "*" in file:
                for wildcard_file in glob.glob(file):
                    if os.path.isdir(wildcard_file):
                        shutil.rmtree(wildcard_file)
                    elif os.path.isfile(wildcard_file):
                        os.remove(wildcard_file)
            else:
                if os.path.isdir(file):
                    shutil.rmtree(file)
                elif os.path.isfile(file):
                    os.remove(file)

    def extract(self):
        Logger.info(f"Extracting {self.download_loc} to {self.extract_to}")
        with zipfile.ZipFile(self.download_loc) as z:
            z.extractall(self.extract_to)

    def add_props(self):
        bin_dir = os.path.join(self.copy_dir, "system", "etc")
        resetprop_rc = os.path.join(
            self.copy_dir, "system/etc/init/resetprop.rc")
        if not os.path.isfile(os.path.join(bin_dir, "resetprop")):
            if not os.path.exists(bin_dir):
                os.makedirs(bin_dir)
            shutil.copy(os.path.join(
                "./bin", self.arch[0], "resetprop"), bin_dir)
            os.chmod(os.path.join(bin_dir, "resetprop"), 0o755)
        if not os.path.isfile(os.path.join(bin_dir, "resetprop.sh")):
            with open(os.path.join(bin_dir, "resetprop.sh"), "w") as f:
                f.write("#!/system/bin/sh\n")
                f.write(
                    "while read line; do /system/etc/resetprop ${line%=*} ${line#*=}; done < /vendor/waydroid.prop\n")
            os.chmod(os.path.join(bin_dir, "resetprop.sh"), 0o755)
        if not os.path.isfile(resetprop_rc):
            if not os.path.exists(os.path.dirname(resetprop_rc)):
                os.makedirs(os.path.dirname(resetprop_rc))
            with open(resetprop_rc, "w") as f:
                f.write(
                    "on post-fs-data\n    exec u:r:su:s0 root root -- /system/bin/sh /system/bin/resetprop.sh")
            os.chmod(resetprop_rc, 0o644)

        cfg = configparser.ConfigParser()
        cfg.read("/var/lib/waydroid/waydroid.cfg")

        for key in self.apply_props.keys():
            if self.apply_props[key]:
                cfg.set('properties', key, self.apply_props[key])

        with open("/var/lib/waydroid/waydroid.cfg", "w") as f:
            cfg.write(f)

    def extract_app_lib(self, apk_file_path):
        lib_dest_dir = os.path.dirname(apk_file_path)
        with zipfile.ZipFile(apk_file_path, "r") as apk:
            for file_info in apk.infolist():
                file_name = file_info.filename
                file_path = os.path.join(lib_dest_dir, file_name)
                if file_info.filename.startswith(f"lib/{self.arch[0]}/") and file_name.endswith(".so"):
                    os.makedirs(os.path.dirname(
                        file_path), exist_ok=True)
                    with apk.open(file_info.filename) as src_file, open(file_path, "wb") as dest_file:
                        # Logger.info(f"{src_file} -> {dest_file}")
                        shutil.copyfileobj(src_file, dest_file)

    def set_path_perm(self, path):
        if "bin" in path.split("/"):
            perms = [0, 2000, 0o755, 0o777]
        else:
            perms = [0, 0, 0o755, 0o644]

        mode = os.stat(path).st_mode

        if os.path.isdir(path):
            mode |= perms[2]
        else:
            mode |= perms[3]

        os.chown(path, perms[0], perms[1])
        os.chmod(path, mode)

    def set_perm2(self, path, recursive=False):
        if not os.path.exists(path):
            return

        if recursive and os.path.isdir(path):
            for root, dirs, files in os.walk(path):
                for dir in dirs:
                    self.set_path_perm(os.path.join(root, dir))
                for file in files:
                    self.set_path_perm(os.path.join(root, file))
        else:
            self.set_path_perm(path)

    def set_perm(self):
        for f in self.files:
            path = os.path.join(self.copy_dir, self.partition, f)
            if "*" in path:
                for wildcard_file in glob.glob(path):
                    self.set_perm2(wildcard_file, recursive=True)
            else:
                self.set_perm2(path, recursive=True)

    def remove_props(self):
        cfg = configparser.ConfigParser()
        cfg.read("/var/lib/waydroid/waydroid.cfg")

        for key in self.apply_props.keys():
            cfg.remove_option('properties', key)

        with open("/var/lib/waydroid/waydroid.cfg", "w") as f:
            cfg.write(f)

    def copy(self):
        pass

    def extra1(self):
        pass

    def extra2(self):
        pass

    def install(self):
        self.download()
        if not self.skip_extract:
            self.extract()
        self.copy()
        self.extra1()
        if hasattr(self, "apply_props"):
            self.add_props()
        self.set_perm()
        Logger.info(f"{self.id} installation finished")

    def uninstall(self):
        self.remove()
        if hasattr(self, "apply_props"):
            self.remove_props()
        self.extra2()
        self.set_perm()
        Logger.info("Uninstallation finished")