import base64
from os import getenv
import html
import json
import re
import requests
import logging
import subprocess

from typing import Any, OrderedDict
from xml.dom import minidom

from requests import Session
from packaging import version

class Prop(OrderedDict):
    def __init__(self, props: str = ...) -> None:
        super().__init__()
        for i, line in enumerate(props.splitlines(False)):
            if '=' in line:
                k, v = line.split('=', 1)
                self[k] = v
            else:
                self[f".{i}"] = line

    def __setattr__(self, __name: str, __value: Any) -> None:
        self[__name] = __value

    def __repr__(self):
        return '\n'.join(f'{item}={self[item]}' for item in self)

logging.captureWarnings(True)
env_file = getenv('GITHUB_ENV')
token = getenv("API_KEY")
authorization = f'Bearer {token}'
reqheaders = {
    "Accept": "application/vnd.github.v3+json",
    "Authorization" : authorization,
}
#Category ID
cat_id = '858014f3-3934-4abe-8078-4aa193e74ca8'

release_type = "WIF"

new_version_found = False

session = Session()
session.verify = False

git = (
    "git checkout -f update || git switch --discard-changes --orphan update"
)

def Magisk_Ksu_Gapps_Checker(type):
    global new_version_found
    # Get current version
    currentver = requests.get(f"https://raw.githubusercontent.com/YT-Advanced/WSA-Script/update/" + type + ".appversion").text.replace('\n', '')
    # Write for pushing later
    file = open('../' + type + '.appversion', 'w')
    file.write(currentver)
    if new_version_found:
        return 0;

    # Get latest version
    latestver = ""
    msg = ""
    if (type == "magisk"):
        latestver = json.loads(requests.get(f"https://github.com/topjohnwu/magisk-files/raw/master/stable.json").content)['magisk']['version'].replace('\n', '')
        msg="Update Magisk Version from `v" + currentver + "` to `v" + latestver + "`"
    elif (type == "gapps"):
        latestver = json.loads(requests.get(f"https://api.github.com/repos/YT-Advanced/MindTheGappsBuilder/releases/latest", headers=reqheaders).content)['name']
        msg="Update MindTheGapps Version from `v" + currentver + "` to `v" + latestver + "`"
    elif (type == "kernelsu"):
        latestver = json.loads(requests.get(f"https://api.github.com/repos/tiann/KernelSU/releases/latest", headers=reqheaders).content)['name']
        msg="Update KernelSU Version from `" + currentver + "` to `" + latestver + "`"

    # Check if version is the same or not
    if (currentver != latestver):
        print("New version found: " + latestver)
        new_version_found = True
        # Write appversion content
        subprocess.Popen(git, shell=True, stdout=None, stderr=None, executable='/bin/bash').wait()
        file.seek(0)
        file.truncate()
        file.write(latestver)
        # Write Github Environment
        with open(env_file, "a") as wr:
            wr.write("SHOULD_BUILD=yes\nMSG=" + msg)
    file.close()

def WSAChecker(user, release_type):
    global new_version_found
    currentver = requests.get(f"https://raw.githubusercontent.com/YT-Advanced/WSA-Script/update/" + release_type + ".appversion").text.replace('\n', '')

    # Write for pushing later
    file = open('../' + release_type + '.appversion', 'w')
    file.write(currentver)

    if new_version_found:
        return 0;
    # Get information
    with open("../xml/GetCookie.xml", "r") as f:
        cookie_content = f.read().format(user)
        f.close()
    try:
        out = session.post(
            'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
            data=cookie_content,
            headers={'Content-Type': 'application/soap+xml; charset=utf-8'}
        )
    except:
        print("Network Error!")
        return 1
    doc = minidom.parseString(out.text)
    cookie = doc.getElementsByTagName('EncryptedData')[0].firstChild.nodeValue
    with open("../xml/WUIDRequest.xml", "r") as f:
        cat_id_content = f.read().format(user, cookie, cat_id, release_type)
        f.close()
    try:
        out = session.post(
            'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
            data=cat_id_content,
            headers={'Content-Type': 'application/soap+xml; charset=utf-8'}
        )
    except:
        print("Network Error!")
        return 1
    doc = minidom.parseString(html.unescape(out.text))
    filenames = {}
    for node in doc.getElementsByTagName('ExtendedUpdateInfo')[0].getElementsByTagName('Updates')[0].getElementsByTagName('Update'):
        node_xml = node.getElementsByTagName('Xml')[0]
        node_files = node_xml.getElementsByTagName('Files')
        if not node_files:
            continue
        else:
            for node_file in node_files[0].getElementsByTagName('File'):
                if node_file.hasAttribute('InstallerSpecificIdentifier') and node_file.hasAttribute('FileName'):
                    filenames[node.getElementsByTagName('ID')[0].firstChild.nodeValue] = (f"{node_file.attributes['InstallerSpecificIdentifier'].value}_{node_file.attributes['FileName'].value}",
                                                                                          node_xml.getElementsByTagName('ExtendedProperties')[0].attributes['PackageIdentityName'].value)
    identities = {}
    for node in doc.getElementsByTagName('NewUpdates')[0].getElementsByTagName('UpdateInfo'):
        node_xml = node.getElementsByTagName('Xml')[0]
        if not node_xml.getElementsByTagName('SecuredFragment'):
            continue
        else:
            id = node.getElementsByTagName('ID')[0].firstChild.nodeValue
            update_identity = node_xml.getElementsByTagName('UpdateIdentity')[0]
            if id in filenames:
                fileinfo = filenames[id]
                if fileinfo[0] not in identities:
                    identities[fileinfo[0]] = ([update_identity.attributes['UpdateID'].value,
                                            update_identity.attributes['RevisionNumber'].value], fileinfo[1])
    wsa_build_ver = 0
    for filename, value in identities.items():
        if re.match(f"MicrosoftCorporationII.WindowsSubsystemForAndroid_.*.msixbundle", filename):
            tmp_wsa_build_ver = re.search(r"\d{4}.\d{5}.\d{1,}.\d{1,}", filename).group()
            if (wsa_build_ver == 0):
                wsa_build_ver = tmp_wsa_build_ver
            elif version.parse(wsa_build_ver) < version.parse(tmp_wsa_build_ver):
                wsa_build_ver = tmp_wsa_build_ver
     
    # Check new WSA version
    if version.parse(currentver) < version.parse(wsa_build_ver):
        print("New version found: " + wsa_build_ver)
        new_version_found = True
        # Write appversion content
        subprocess.Popen(git, shell=True, stdout=None, stderr=None, executable='/bin/bash').wait()
        file.seek(0)
        file.truncate()
        file.write(wsa_build_ver)
        # Write Github Environment
        msg = 'Update WSA Version from `v' + currentver + '` to `v' + wsa_build_ver + '`'
        with open(env_file, "a") as wr:
            wr.write("SHOULD_BUILD=yes\nRELEASE_TYPE=" + release_type + "\nMSG=" + msg)
    file.close()

# Get user_code (Thanks to @bubbles-wow because of his repository)
users = {""}
try:
    response = requests.get("https://api.github.com/repos/bubbles-wow/WSAUpdateChecker/contents/token.conf")
    if response.status_code == 200:
        content = response.json()["content"]
        content = content.encode("utf-8")
        content = base64.b64decode(content)
        text = content.decode("utf-8")
        user_code = Prop(text).get("user_code")
        updatetime = Prop(text).get("update_time")
        print("Successfully get user token from server!")
        print(f"Last update time: {updatetime}\n")
    else:
        user_code = ""
        print(f"Failed to get user token from server! Error code: {response.status_code}\n")
except:
    user_code = ""

if user_code == "":
    users = {""}
else:
    users = {"", user_code}
for user in users:
    if user == "":
        print("Checking WSA Stable version...\n")
        if WSAChecker(user, "retail") == 1:
            break
        print("Checking Magisk version...\n")
        if Magisk_Ksu_Gapps_Checker("magisk") == 1:
            break
        print("Checking KernelSU version...\n")
        if Magisk_Ksu_Gapps_Checker("kernelsu") == 1:
            break
        print("Checking MindTheGapps version...\n")
        if Magisk_Ksu_Gapps_Checker("gapps") == 1:
            break
    else:
        print("Checking WSA Insider version...\n")
        if WSAChecker(user, "WIF") == 1:
            break
