package net.geedge.api.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.log.Log;
import net.geedge.common.Constant;
import net.geedge.common.T;

import java.io.*;
import java.util.Base64;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class ApkUtil {

    private static final Log log = Log.get();

    public static final String APPLICATION = "application:";
    public static final String APPLICATION_ICON = "application-icon";
    public static final String APPLICATION_LABEL = "application-label";
    public static final String APPLICATION_LABEL_N = "application: label";
    public static final String DENSITIES = "densities";
    public static final String LAUNCHABLE_ACTIVITY = "launchable";
    public static final String PACKAGE = "package";
    public static final String SDK_VERSION = "sdkVersion";
    public static final String SUPPORTS_ANY_DENSITY = "support-any-density";
    public static final String SUPPORTS_SCREENS = "support-screens";
    public static final String TARGET_SDK_VERSION = "targetSdkVersion";
    public static final String VERSION_CODE = "versionCode";
    public static final String VERSION_NAME = "versionName";
    public static final String USES_FEATURE = "uses-feature";
    public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";
    public static final String USES_PERMISSION = "uses-permission";

    private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";

    private ProcessBuilder builder;
    // aapt 所在目录
    private String aaptToolPath = "aapt";

    public ApkUtil() {
        builder = new ProcessBuilder();
        builder.redirectErrorStream(true);
    }

    public String getAaptToolPath() {
        return aaptToolPath;
    }

    public void setAaptToolPath(String aaptToolPath) {
        this.aaptToolPath = aaptToolPath;
    }

    public ApkInfo parseApk(String apkPath) {
        String aaptTool = aaptToolPath;
        Process process = null;
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            process = builder.command(aaptTool, "d", "badging", apkPath).start();
            inputStream = process.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            ApkInfo apkInfo = new ApkInfo();
            apkInfo.setSize(new File(apkPath).length());
            String temp = null;
            while ((temp = bufferedReader.readLine()) != null) {
                setApkInfoProperty(apkInfo, temp);
            }
            return apkInfo;
        } catch (IOException e) {
            log.error(e, "[parseApk] [error]");
            return null;
        } finally {
            if (process != null) {
                process.destroy();
            }
            T.IoUtil.close(inputStream);
            T.IoUtil.close(bufferedReader);
        }
    }

    private void setApkInfoProperty(ApkInfo apkInfo, String source) {
        if (source.startsWith(APPLICATION)) {
            String[] rs = source.split("( icon=')|'");
            apkInfo.setIcon(rs[rs.length - 1]);
        } else if (source.startsWith(APPLICATION_ICON)) {
            apkInfo.addToIcons(getKeyBeforeColon(source), getPropertyInQuote(source));
        } else if (source.startsWith(APPLICATION_LABEL)) {
            apkInfo.setLabel(getPropertyInQuote(source));
        } else if (source.startsWith(LAUNCHABLE_ACTIVITY)) {
            apkInfo.setLaunchableActivity(getPropertyInQuote(source));
        } else if (source.startsWith(PACKAGE)) {
            String[] packageInfo = source.split(SPLIT_REGEX);
            apkInfo.setPackageName(packageInfo[2]);
            apkInfo.setVersionCode(packageInfo[4]);
            apkInfo.setVersionName(packageInfo[6]);
        } else if (source.startsWith(SDK_VERSION)) {
            apkInfo.setSdkVersion(getPropertyInQuote(source));
        } else if (source.startsWith(TARGET_SDK_VERSION)) {
            apkInfo.setTargetSdkVersion(getPropertyInQuote(source));
        } else if (source.startsWith(USES_PERMISSION)) {
            apkInfo.addToUsesPermissions(getPropertyInQuote(source));
        } else if (source.startsWith(USES_FEATURE)) {
            apkInfo.addToFeatures(getPropertyInQuote(source));
        }
    }

    private String getKeyBeforeColon(String source) {
        return source.substring(0, source.indexOf(':'));
    }

    private String getPropertyInQuote(String source) {
        int index = source.indexOf("'") + 1;
        return source.substring(index, source.indexOf('\'', index));
    }

    public String extractFileFromApk(String apkPath, String fileName) {
        ZipFile zipFile = null;
        File tempIconFile = T.FileUtil.file(Constant.TEMP_PATH, T.IdUtil.fastSimpleUUID());
        try {
            zipFile = new ZipFile(apkPath);
            ZipEntry entry = zipFile.getEntry(fileName);
            InputStream inputStream = zipFile.getInputStream(entry);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempIconFile), 1024);
            byte[] b = new byte[1024];
            BufferedInputStream bis = new BufferedInputStream(inputStream, 1024);
            while (bis.read(b) != -1) {
                bos.write(b);
            }
            IoUtil.flush(bos);
            T.IoUtil.close(bos);
            T.IoUtil.close(bis);
            T.IoUtil.close(inputStream);
            T.IoUtil.close(zipFile);

            String base64Str = Base64.getEncoder().encodeToString(T.FileUtil.readBytes(tempIconFile));
            return base64Str;
        } catch (IOException e) {
            log.error(e, "[extractFileFromApk] [error]");
        } finally {
            T.FileUtil.del(tempIconFile);
            T.IoUtil.close(zipFile);
        }
        return null;
    }
}