import os
import re
import shutil
import ssl
import urllib.request
from urllib.error import URLError

import regex as re2
import requests

ssl._create_default_https_context = ssl._create_unverified_context


def sub_map_text(mapping, is_reverse=True, path='.', skip_type=None, skip_name=None):
    if len(mapping) == 0:
        return []
    if skip_type is None:
        skip_type = []
    if skip_name is None:
        skip_name = []
    result = []
    sub_map_text_impl(mapping, result, skip_type, skip_name, is_reverse, path)
    return result


def sub_map_text_impl(mapping, result, skip_type, skip_name, is_reverse=True, path='.'):
    listdir = os.listdir(path)
    for i in listdir:
        path_join = os.path.join(path, i)
        if os.path.isdir(path_join):
            if path.endswith('.') and i in ["build", "debug", "release"]:
                continue
            if path.endswith('src') and i in ["androidTest", "test"]:
                continue
            sub_map_text_impl(mapping, result, skip_type, skip_name, is_reverse, path_join)
        elif os.path.isfile(path_join):
            if path.endswith('.') and i.split('.')[-1] in ['py']:
                continue
            if i.split('.')[-1] in skip_type:
                continue
            is_skip = False
            for j in skip_name:
                if j in i:
                    is_skip = True
                    break
            if is_skip:
                continue
            with open(path_join, 'r', encoding='utf-8') as f:
                if not f.readable():
                    continue
                try:
                    text = f.read()
                except ValueError:
                    continue
            with open(path_join, 'w', encoding='utf-8') as f:
                reverse = sorted(list(mapping.keys()), key=len, reverse=is_reverse)
                text_result = text
                for name in reverse:
                    text_result = re2.sub(str(name), mapping[name], text_result)
                if text_result != text:
                    result.append(path_join)
                f.write(text_result)


def copy_folder_exclude(src, dst, exclude_names=None):
    if exclude_names is None:
        exclude_names = []

    if not os.path.exists(dst):
        os.makedirs(dst)

    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)

        if item in exclude_names:
            continue

        if os.path.isdir(s):
            copy_folder_exclude(s, d, exclude_names)
        else:
            shutil.copy2(s, d)


def get_desktop_path():
    # Windows 系统
    if os.name == 'nt':
        desktop = os.path.join(os.getenv('USERPROFILE'), 'Desktop')
    # macOS 系统
    elif os.name == 'posix':
        desktop = os.path.join(os.getenv('HOME'), 'Desktop')
    # Linux 或其他 Unix-like 系统可能需要手动指定
    else:
        desktop = os.path.join(os.getenv('HOME'), 'Desktop')  # 可能的默认位置
    return desktop


def find_text_impl(reg, result, skip_name, path, is_one):
    listdir = os.listdir(path)
    for i in listdir:
        if is_one and len(result) > 0:
            return
        path_join = os.path.join(path, i)
        if os.path.isdir(path_join):
            if path.endswith('.') and i in ["build", "debug", "release"]:
                continue
            if path.endswith('src') and i in ["androidTest", "test"]:
                continue
            find_text_impl(reg, result, skip_name, path_join, is_one)
        elif os.path.isfile(path_join):
            if path.endswith('.') and i.split('.')[-1] in ['py']:
                continue
            is_skip = False
            for j in skip_name:
                if j in i:
                    is_skip = True
                    break
            if is_skip:
                continue
            with open(path_join, 'r', encoding='utf-8') as f:
                if not f.readable():
                    continue
                try:
                    text = f.read()
                except ValueError:
                    continue
                findall = re.findall(reg, text)
                if len(findall) > 0:
                    result.extend(findall)


def find_text(reg, path='.', is_one=False, skip_name=None):
    if skip_name is None:
        skip_name = []
    result = []
    if os.path.isdir(path):
        find_text_impl(reg, result, skip_name, path, is_one)
    else:
        with open(path, 'r', encoding='utf-8') as f:
            if f.readable():
                try:
                    text = f.read()
                    findall = re.findall(reg, text)
                    if len(findall) > 0:
                        result.extend(findall)
                except ValueError:
                    pass
    if is_one:
        return result[0]
    return result


def get_path(path):
    return path.replace('\\', os.path.sep)


def main():
    isMinifyEnabled = find_text('release ?{\\s*?(?:isM|m)inifyEnabled(?: ?= ?| )(false|true)', is_one=True)
    if isMinifyEnabled == 'false':
        print('官方混淆未开启')
        exit()

    # 测试包名
    applicationId = find_text('applicationId .*?["\'](.*?)["\']', is_one=True)
    # 正式包名
    packageName_id = find_text('packageName = R.string.(\\w+?).string\\(\\)', is_one=True)
    packageName_id = ''.join(['\\u' + format(ord(c), '04x') for c in packageName_id[:-2]]) + '_D'
    packageName = find_text('"(.*?)": "' + re.escape(packageName_id) + '"', is_one=True)

    sub_map = {
        applicationId: packageName
    }
    print('包名: %s -> %s' % (applicationId, packageName))

    res = requests.get(
        url="http://data-api.zhangxinhulian.com/cms/add/apps_info/getBuildCfg?tgyz=1",
        params={"pkg": packageName}
    )
    data = res.json()['result']['data']
    print(data)
    fileUrl = data['fileUrl']
    adIds = data.get('buildCfg')
    eventUrl = data['reportDomain']
    apiUrl = data['apiDomain']
    facebookId = data['facebookApId']
    configString = data['appCfg']

    if adIds is not None:
        admobId = adIds['admobApplicationId']
        openId = adIds['admobOpenAdId']
        interId = adIds['admobInternalAdId']
        nativeId = adIds['admobNativeAdId']
        rewardId = adIds['admobRewardAdId']

        if admobId is not None:
            sub_map['(?<="com.google.android.gms.ads.APPLICATION_ID"\\s*?android:value=")[\\w~-]*?(?=")'] = admobId
        if openId is not None:
            sub_map['(?<=val openAdmobId = )\\S*'] = '"' + openId + '"'
        if interId is not None:
            sub_map['(?<=val interAdmobId = )\\S*'] = '"' + interId + '"'
        if nativeId is not None:
            sub_map['(?<=val nativeAdmobId = )\\S*'] = '"' + nativeId + '"'
        if rewardId is not None:
            sub_map['(?<=val rewardAdmobId = )\\S*'] = '"' + rewardId + '"'

    if eventUrl is not None:
        sub_map['(?<=val eventUrl = )\\S*'] = '"' + eventUrl + '"'

    if apiUrl is not None:
        sub_map['(?<=val apiUrl = )\\S*'] = '"' + apiUrl + '"'

    if configString is not None:
        sub_map['(?<=var configString = )\\S*'] = '"' + configString + '"'
    sub_map_text(sub_map)

    if facebookId is None:
        print('后台facebookId 未配置')
    elif len(find_text('<string name=".*?">' + facebookId + '</string>')) == 0:
        print('facebook 配置出错')

    try:
        urllib.request.urlretrieve(fileUrl, 'google-services.json')
        print('google-services.json 替换成功')
    except URLError as e:
        print('google-services.json 替换失败')
        print(e)
        return

    input('回车开始压缩(\\n)')

    versionName = find_text('versionName.*?"(.*?)"', is_one=True)
    path = os.path.abspath(get_path('..\\'))
    new_path = os.path.join(get_desktop_path(), os.path.basename(path) + '_' + versionName)
    exclusions = ['.git', '.gradle', '.idea', 'build', '.gitignore', 'local.properties', '.gitignore', 'mapping.json', 'packing.py', 'proguard.py', 'release', 'debug']
    copy_folder_exclude(path, new_path, exclusions)
    shutil.make_archive(new_path, 'zip', new_path)
    shutil.rmtree(new_path)
    print('Done!')


if __name__ == '__main__':
    main()
