#!/usr/bin/python3

import typing
import os
import shutil
import subprocess
from json import load as jload
from os import chdir, path, system, unlink, walk
import urllib.request


verbose = True
stdout = subprocess.PIPE if verbose else subprocess.DEVNULL
stderr = subprocess.STDOUT if verbose else subprocess.DEVNULL

with open('settings.json') as f:
    config = jload(f)

if not os.path.isfile("discord.apk"):
    print("[Download] Downloading Discord APK...")

    code = system(f'curl -L {config["download_url"]} -o discord.apk')
    if code != 0:
        print("[Download] Failed to download APK!")
        raise SystemExit(code)

    '''
    apk_url = config["download_url"]

    while True:
        try:
            req = urllib.request.urlopen(apk_url)
            print(req.read())
            req.close()
        except Exception as e:
            if e.code == 403:
                apk_url = e.geturl()
                continue
            print(e)
            raise SystemExit("[Download] Failed to download APK!")
    '''
    print("[Download] APK Downloaded")
else:
    print("[Download] APK already downloaded")



print("[Decompile] Decompiling APK, this may take a minute...")
r = subprocess.Popen('java -jar apktool.jar d -f discord.apk', shell=True, text=True, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr)
r.stdin.write('\r\n' if os.name=='nt' else '\n')
r.communicate()
chdir('discord')

# Things that need some renaming to actually work correctly should be edited and reviewed here every update
bugfixes = []

protocol = ('http://', 'ws://')
if config['secure']:
    protocol = ('https://', 'wss://')

# Basic replacements throughout the code to replace discord routes with fosscord routes
# NOTE: Order of replacements is VERY important and will probably have to do stupid stuff to make it customisable
replacements = [
  ('https://cdn.discordapp.com', protocol[0]+config['cdn_url']), # cdn.discord.com to cdn url
  ('https://media.discordapp.net', protocol[0]+config['cdn_url']), # discord media proxy to cdn url
  ('https://gateway.discord.gg', protocol[1]+config['gateway_url']), # gateway.discord.com to gateway url
  ('https://discord.com', protocol[0]+config['base_url']), # discord.com to the base url
  ('https://discordapp.com', protocol[0]+config['base_url']), # Extra change just in case discordapp is still used in the code somewhere
  ('https://discord.gg', protocol[0]+config['invite_url']), # discord.gg to the invite url
  ('https://discord.new/', protocol[0]+config['base_url']+'/template') # discord.new to template url
]

if config.get('debug'):
    replacements.append(("DEBUG:Z = false", "DEBUG:Z = true")) # Enables debug if it's true in the config

def patchfile(file):
    code = system("patch -p1 --no-backup-if-mismatch -i ../patches/"+file)
    if code != 0:
        print(f"[PatchFile] Failed to apply patchfile {file}")
        return
    if verbose:
        print(f"[PatchFile] Applied patchfile {file}")

def patch(folder):
    for root, _, files in walk(path.join('.', folder)):
        for file in files:
            fpath = path.join(root, file)
            try:
                with open(fpath) as f:
                    data = tmp = f.read()
                for bugfix in bugfixes:
                    data = data.replace(*bugfix)
                for replacement in replacements:
                    data = data.replace(*replacement)
                if tmp != data:
                    with open(fpath, 'w+') as f:
                        f.write(data)
                    if verbose:
                        print(f"[Patch] Applied patches to `{fpath}`")
            except UnicodeDecodeError:
                pass

print("[Patcher] Patching...")
patch('smali')
patch('smali_classes2')
patch('smali_classes3')

print("[Patcher] Patching AndroidManifest.xml...")
with open('AndroidManifest.xml') as f:
    manifest = f.read()
    # manifest = manifest.replace(config['original_package_name'], config['new_package_name'])
    if config["old_app_name"] != config["new_app_name"]:
        manifest = manifest.replace(config['old_app_name'], config['new_app_name'])
    if verbose:
        print("[Patcher] Patched AndroidManifest.xml")

    with open('AndroidManifest.xml', 'w') as f:
        f.write(manifest)

print("[Patcher] Patching complete")
chdir('..')

'''
print("[Icon] Replacing icon...")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-hdpi/ic_logo_round.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-hdpi/ic_logo_square.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xhdpi/ic_logo_round.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xhdpi/ic_logo_square.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxhdpi/ic_logo_round.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxhdpi/ic_logo_square.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxhdpi/logo.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxxhdpi/ic_logo_round.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxxhdpi/ic_logo_square.png")
shutil.copyfile("assets/icon.png", "discord/res/mipmap-xxxhdpi/logo.png")
'''

print("[Build] Rebuilding APK...")
r = subprocess.Popen('apktool b discord/ -o fosscord.unsigned.apk', shell=True, text=True, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr)
r.stdin.write('\r\n' if os.name=='nt' else '\n')
r.communicate()
print("[Build] APK rebuilt")

print("[Sign] Signing APK...")
r = subprocess.Popen('java -jar uber-apk-signer.jar --apks fosscord.unsigned.apk -o .', shell=True, text=True, stdout=stdout, stderr=stderr)
r.communicate()
print("[Sign] APK signed")

'''
print("[Clean] Cleaning up...")
shutil.rmtree("discord")
unlink("fosscord.unsigned.apk")
'''

print("All done!")
