#!/usr/bin/env python3.2
import os, sys, subprocess, shutil, time, re, random, json
from helpers import *

VAR_INSTALLER_PPS = "/var/pps/system@0.0.777/installer@88.88.755/upd@88.88.755/current@88.88.2775"
INSTALLER_PPS = "/pps/system/installer/upd/current"
INSTALL_DIR = "/var/android"
TEMP_DIR = "/accounts/1000/shared/documents/tmp"
SILENT_INSTALL = False

def initialSetup():
    if os.path.exists(TEMP_DIR):
        shutil.rmtree(TEMP_DIR, ignore_errors=True)
    runQnxCommandWait('echo "chmod -R 777 %s" | /q/__pps' % VAR_INSTALLER_PPS)
    os.makedirs(TEMP_DIR, exist_ok=True)
    for root, dirs, files in os.walk(TEMP_DIR):
        for d in dirs:
            os.chmod(os.path.join(root, d), 0o777);

def controlledPrint(*args, **kwargs):
    if not SILENT_INSTALL:
        print(*args, **kwargs)

def controlledLedControl(state):
    if not SILENT_INSTALL:
        ledControl(state)

def hasArg(arg):
    return arg in sys.argv

def installPackage(packagePath, alwaysOverwrite=False):
    if not os.path.exists(packagePath):
        return
        
    tmpPkg = "app%s" % random.randint(10000,99999)
    pkgContent = os.path.join(TEMP_DIR, tmpPkg)
    controlledPrint("Unpacking", packagePath, "...")
    subprocess.call(["unzip", "-o", "-q", "-X", packagePath, "-d", pkgContent])
    for root, dirs, files in os.walk(pkgContent):
        for d in dirs:
            os.chmod(os.path.join(root, d), 0o777)
        for f in files:
            os.chmod(os.path.join(root, f), 0o777)

    mfPath = os.path.join(pkgContent, "META-INF", "MANIFEST.MF")
    if not os.path.exists(mfPath):
        controlledPrint("No META-INF directory found, package invalid.")
        shutil.rmtree(pkgContent, ignore_errors=True)
        return

    with open(mfPath) as f:
        manifest = f.read()
    
    packageId = re.search(r'Package-Id.*:\s*(.*)', manifest).group(1).strip()
    packageName = re.search(r'Package-Name.*:\s*(.*)', manifest).group(1).strip()
    packageVersionId = re.search(r'Package-Version-Id.*:\s*(.*)', manifest).group(1).strip()
    required = ".installer/required/" in packagePath

    rdkFile = os.path.join(pkgContent, "META-INF", "RDK.EC")
    authorFile = os.path.join(pkgContent, "META-INF", "AUTHOR.EC")
    signed = os.path.exists(rdkFile) and os.path.exists(authorFile) and packageId.startswith("gYAB")

    controlledPrint("\033[H\033[J", end="")
    controlledPrint("---------------------------------")
    controlledPrint("Package ID:", packageId)
    controlledPrint("Package Name:", packageName)
    controlledPrint("Package Version:", packageVersionId)
    controlledPrint("Required:", "Yes" if required else "No")
    controlledPrint("---------------------------------")
    existingAppId = getAppId(packageName)
    if existingAppId and not alwaysOverwrite and not required:
        result = showDialog(
            id="dlg",
            title="Package already installed",
            message="Package %s is already installed. Do you want to overwrite it?" % packageName,
            buttons=[
                {
                    "label": "Yes",
                },
                {
                    "label": "No",
                }
            ]
        )

        if result["resp_obj"]["responseBtnLabel"] == "No":
            controlledPrint("Installation cancelled.")
            shutil.rmtree(pkgContent, ignore_errors=True)
            return

    controlledPrint("Installing ...")
    controlledLedControl({"blue": True, "red": True, "green": True})
    if not signed:
        if packageId.startswith("gYAB"):
            packageId.replace("gYAB", "andrB")
            manifest = re.sub(r'Package-Id.*:\s*.*', 'Package-Id: %s' % packageId, manifest)
            
        if packageVersionId.startswith("gYAC"):
            packageVersionId = packageVersionId.replace("gYAC", "andrC")
            manifest = re.sub(r'Package-Version-Id.*:\s*.*', 'Package-Version-Id: %s' % packageVersionId, manifest)

        with open(mfPath, "w") as f:
            f.write(manifest)

        postBootDir = os.path.join(INSTALL_DIR, "postBoot"+packageId)
        currentDir = os.path.join(INSTALL_DIR, "current"+packageId)

        dirsToRemove = [
            postBootDir,
            currentDir
        ]

        for d in dirsToRemove:
            if fileExistsAsAny(d, ["/q/g_nto", "/q/__upd", "/q/__apps", "/q/__devuser"]):
                try :
                    runQnxCommandWait("echo \"rm -rf %s\" | /q/g_nto" % d)
                    runQnxCommandWait("echo \"rm -rf %s\" | /q/__upd" % d)
                    runQnxCommandWait("echo \"rm -rf %s\" | /q/__apps" % d)
                    runQnxCommandWait("echo \"rm -rf %s\" | /q/__devuser" % d)
                except Exception as e:
                    controlledPrint("Error removing old directory:", d, e)

        runQnxCommandWait("echo \"chmod -R 777 %s\" | /q/__upd" % postBootDir)
        runQnxCommandWait("echo \"chmod -R 777 %s\" | /q/__upd" % currentDir)
        runQnxCommandWait("echo \"chmod 777 %s\" | /q/__upd" % postBootDir)
        runQnxCommandWait("echo \"chmod 777 %s\" | /q/__upd" % currentDir)

        try:
            shutil.copytree(pkgContent, postBootDir)
        except Exception as e:
            controlledPrint("Error copying for post-boot install")

        try:
            shutil.copytree(pkgContent, currentDir)
        except Exception as e:
            controlledPrint("Error copying for runtime install")

        runQnxCommandWait("echo \"chmod -R 777 %s\" | /q/__upd" % postBootDir)
        runQnxCommandWait("echo \"chmod -R 777 %s\" | /q/__upd" % currentDir)
        runQnxCommandWait("echo \"chmod 777 %s\" | /q/__upd" % postBootDir)
        runQnxCommandWait("echo \"chmod 777 %s\" | /q/__upd" % currentDir)
        postBootInstall = "@%s\naction::install_apk\npackage_location::%s\nextras::source::apk\n" % (packageId, postBootDir)
        runQnxCommandWait("echo \"rm -rf %s/bootInstall.%s@88.88.777\" | /q/__pps" % (VAR_INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"echo '%s' > %s/bootInstall.%s@88.88.777\" | /q/__pps" % (postBootInstall, VAR_INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"chmod 777 %s/bootInstall.%s@88.88.777\" | /q/__pps" % (VAR_INSTALLER_PPS, packageId))

        runtimeInstall = "@%s\naction::install_apk\npackage_location::%s\nextras::source::apk\n" % (packageId, currentDir)
        runQnxCommandWait("echo \"rm -rf %s/runtimeInstall.%s\" | /q/__upd" % (INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"echo '%s' > %s/runtimeInstall.%s\" | /q/__upd" % (runtimeInstall, INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"chmod 777 %s/runtimeInstall.%s\" | /q/__upd" % (INSTALLER_PPS, packageId))
    else:
        installerPackagePath = os.path.join(INSTALL_DIR, packageId + ".bar");
        if os.path.exists(installerPackagePath):
            if fileExistsAs(installerPackagePath, "/q/__upd"):
                runQnxCommandWait("echo \"rm -rf %s\" | /q/__upd" % installerPackagePath)

        shutil.copy(packagePath, installerPackagePath)
        runQnxCommandWait("chmod 777 %s" % (installerPackagePath))
        runtimeInstall = "@%s\naction::install\npackage_location::%s\nextras::\n" % (packageId, installerPackagePath)
        runQnxCommandWait("echo \"rm -rf %s/runtimeInstall.%s\" | /q/__upd" % (INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"echo '%s' > %s/runtimeInstall.%s\" | /q/__upd" % (runtimeInstall, INSTALLER_PPS, packageId))
        runQnxCommandWait("echo \"chmod 777 %s/runtimeInstall.%s\" | /q/__upd" % (INSTALLER_PPS, packageId))

    controlledLedControl({"blue": True, "red": True, "green": False})
    command = "echo \"cat %s/runtimeInstall.%s\" | /q/__upd | grep result::" % (INSTALLER_PPS, packageId)
    catOut, _ = runQnxCommandWait(command)
    installationResult = catOut.decode().strip()
    
    while not installationResult:
        time.sleep(0.5)
        catOut, _ = runQnxCommandWait(command)
        installationResult = catOut.decode().strip()

    if "result::success" in installationResult:
        controlledLedControl({"blue": False, "red": False, "green": True})
        controlledPrint("Package installed successfully.")
        if required:
            controlledPrint("This package is required, setting permanent flag.")
            appId = getAppId(packageName)
            if appId:
                setPermanentFlag(appId, True)
    else:
        controlledPrint("Package installation failed.")
        controlledLedControl({"blue": False, "red": True, "green": False})
        if "result::failure" in installationResult:
            controlledPrint("Error:", installationResult.split("result::failure")[1].strip())
        else:
            controlledPrint("Unknown error occurred.")

    controlledPrint("Cleaning up temporary files...")
    runQnxCommandWait("echo \"rm -rf %s\" | /q/__upd" % currentDir)
    shutil.rmtree(pkgContent, ignore_errors=True)
    time.sleep(1)
    controlledLedControl({"blue": False, "red": False, "green": False})

def getVarPPSPath():
    command = "cd /var/pps/system@*/installer@*/upd@*/current@*; echo RESULT::$(pwd)"
    out, _ = runAs(command, getImpersonation("user", "pps"))
    outputText = out.decode().strip()
    if "RESULT::" in outputText:
        return outputText.split("RESULT::")[1].strip().split("\n")[0]
    return VAR_INSTALLER_PPS

def main():
    initialSetup()
    if (hasArg("--silent")):
        global SILENT_INSTALL
        SILENT_INSTALL = True

    if (hasArg("--startup")):
        controlledPrint("Running startup installations...")
        requiredPath = "/accounts/1000/shared/.installer/required"
        if os.path.isdir(requiredPath):
            for f in os.listdir(requiredPath):
                if f.lower().endswith(".bar"):
                    installPackage(os.path.join(requiredPath, f), alwaysOverwrite=True)
        controlledPrint("Startup installations completed.")
        if os.path.exists(TEMP_DIR):
            shutil.rmtree(TEMP_DIR, ignore_errors=True)
        return
    
    VAR_INSTALLER_PPS = getVarPPSPath()
    controlledPrint("Processing packages...")
    time.sleep(2)
    if len(sys.argv) < 2:
        checkPaths = [
            "/accounts/1000/shared/.installer/required",
            "/accounts/1000/removable/sdcard/documents/packages",
            "/accounts/1000/removable/sdcard/downloads",
            "/accounts/1000/shared/misc/packages",
            "/accounts/1000/shared/documents/packages",
            "/accounts/1000/shared/downloads",
        ]

        for pth in checkPaths:
            if os.path.isdir(pth):
                for f in os.listdir(pth):
                    if f.lower().endswith(".bar"):
                        installPackage(os.path.join(pth, f))
    else:

        if os.path.isfile(sys.argv[1]):
            installPackage(sys.argv[1])
        else:
            controlledPrint("Invalid package path, skipping...")

    if os.path.exists(TEMP_DIR):
        shutil.rmtree(TEMP_DIR, ignore_errors=True)
    controlledPrint("All packages processed.")

if __name__ == "__main__":
    main()
