package com.secspace.lib.common.utils;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by SKR-CYW on 2016/10/15.
 */

public class PkgManager {
    private static final String TAG = "PkgManager";
    private static PkgManager mInstance = null;
    private Context mContext;
    private PackageManager mPackageManager;

    private PkgManager(Context context) {
        this.mContext = context;
        mPackageManager = mContext.getPackageManager();
    }

    public static PkgManager getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new PkgManager(context);
        }
        return mInstance;
    }

    public List<PackageInfo> getAllPackageInfo(int flags) {
        List<PackageInfo> mInstalledPackageInfoList = mPackageManager.getInstalledPackages(flags);
        return mInstalledPackageInfoList;
    }

    public PackageInfo getPackageInfo(String packageName) {
        PackageInfo packageInfo = null;
        try {
            packageInfo = mPackageManager.getPackageInfo(packageName, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return packageInfo;
    }

    public List<String> getAllPackages(int flags) {
        List<PackageInfo> packageInfos = getAllPackageInfo(flags);
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < packageInfos.size(); i++) {
            list.add(packageInfos.get(i).packageName);
        }
        return list;
    }

    /**
     * 获取本地文件apk的versionname
     *
     * @param apkPath
     * @return
     */
    public String getStorageApkVersionName(String apkPath) {
        PackageInfo info = mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        if (info != null) {
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
            return info.versionName;
        }
        return "0";
    }

    /**
     * 获取本地文件apk的versionname
     *
     * @param apkPath
     * @return
     */
    public int getStorageApkVersionCode(String apkPath) {
        PackageInfo info = mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        if (info != null) {
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
            return info.versionCode;
        }
        return -1;
    }

    /**
     * 获取本地文件apk的包名
     *
     * @param apkPath
     * @return
     */
    public String getStorageApkPackgeName(String apkPath) {
        PackageInfo info = mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        String packageName = null;
        if (info != null) {
            ApplicationInfo appInfo = info.applicationInfo;
            packageName = appInfo.packageName;
        }
        return packageName;
    }

    /**
     * @param apkPath
     * @return
     */
    public PackageInfo getStorageApkPackgeInfo(String apkPath) {
        return mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
    }

    /**
     * 获取本地文件apk icon
     *
     * @param apkPath
     * @return
     */
    public Drawable getStorageApkIcon(String apkPath) {
        PackageInfo info = mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        if (info != null) {
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
            try {
                return appInfo.loadIcon(mPackageManager);
            } catch (OutOfMemoryError e) {
                Log.e("ApkIconLoader", e.toString());
            }
        }
        return null;
    }

    /**
     * 获取本地文件apk 名称
     *
     * @param apkPath
     * @return
     */
    public String getStorageApkName(String apkPath) {
        PackageInfo info = mPackageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        String label = null;
        if (info != null) {
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
            label = appInfo.loadLabel(mPackageManager).toString();
        }
        return label;
    }

    /**
     * 安装apk  系统方法
     * android.permission.INSTALL_PACKAGES(system权限)
     *
     * @param apkPath
     */
    public void silentInstallCommon(String apkPath) {
        try {
            mPackageManager
                    .getClass().getMethod("installPackage", Uri.class, Class.forName("android.content.pm.IPackageInstallObserver"), int.class, String.class)
                    .invoke(mContext.getPackageManager(), Uri.fromFile(new File(apkPath)), null,
                            mContext.getPackageManager().getClass().getField("INSTALL_REPLACE_EXISTING").get(null), null);
            Log.i(TAG, "install apk success");
        } catch (Exception e) {
            Log.i(TAG, "install apk", e);
        }
    }

    /**
     * android.permission.DELETE_PACKAGES(system权限)
     *
     * @param packageName
     */
    public void silentUninstallCommon(String packageName) {
        try {
            mPackageManager
                    .getClass().getMethod("deletePackage", String.class, Class.forName("android.content.pm.IPackageDeleteObserver"),
                    int.class).invoke(mContext.getPackageManager(), packageName, null, 0);
            Log.i(TAG, "delete apk success");
        } catch (Exception e) {
            Log.i(TAG, "delete apk", e);
        }
    }

    /**
     * 系统安装器卸载apk
     *
     * @param packageName
     */
    public void uninstallByInstaller(String packageName) {
        Uri packageURI = Uri.parse("package:" + packageName);
        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
        uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(uninstallIntent);
    }

    /**
     * 判断本地文件中的apk是否已安装
     *
     * @param packagename
     * @param apkPath
     * @return
     */
    public boolean isStorageApkInstalled(String packagename, String apkPath) {
        try {
//            PackageInfo localPackageInfo = localPackageManager.getPackageInfo(packagename, PackageManager.GET_UNINSTALLED_PACKAGES);
            PackageInfo localPackageInfo = mPackageManager.getPackageInfo(packagename, 0);
            //apk文件的版本与安装的版本相同才认为是安装了
            if (getStorageApkVersionName(apkPath).equals(localPackageInfo.versionName)) {
                return true;
            }
        } catch (PackageManager.NameNotFoundException localNameNotFoundException) {
            return false;
        }

        return false;
    }

    /**
     * 正常调用系统packageinstall.apk安装
     * action 为：android.intent.action.INSTALL_PACKAGE
     *
     * @param path
     * @return
     */
    public void installByInstaller(String path) {
        File apkFile = new File(path);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                Uri contentUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".fileProvider", apkFile);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            } else {
                intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
            }
        } catch (Exception e) {
            e.printStackTrace();
            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }

    /**
     * 判断应用是否安装
     *
     * @param packageName
     * @return
     */
    public boolean isInstalled(String packageName, String version) {
        try {
            PackageInfo applicationInfo = mPackageManager.getPackageInfo(packageName, 0);
            if (applicationInfo == null) {
                return false;
            }
            Log.d(TAG, "isInstalled version: " + version );
            Log.d(TAG, "isInstalled applicationInfo.versionName: " + applicationInfo.versionName );
            if (version.compareTo(applicationInfo.versionName) > 0) {
                return false;
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean isInstalled(String packageName) {
        try {
            PackageInfo applicationInfo = mPackageManager.getPackageInfo(packageName, 0);
            if (applicationInfo == null) {
                return false;
            }
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
        return true;
    }


    public String getVersionNameFromPackage(String packageName) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
            return packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return "";
    }

    public int getVersionCodeFromPackage(String packageName) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public String getAppNameFromPackage(String packageName) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
            if (packageInfo == null)
                return "UnKnow";
            if (packageInfo.applicationInfo == null)
                return "UnKnow";
            return (String) packageInfo.applicationInfo.loadLabel(mPackageManager);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return "UnKnow";
    }

    public Intent getLauncherIntent(String packageName) {
        //<category android:name="com.skr.security" /> skr版
        Intent intent = null;
        intent = mPackageManager.getLaunchIntentForPackage(packageName);
        if (intent == null) {
            intent = new Intent();
            intent.setAction(Intent.ACTION_MAIN);
            intent.addCategory("com.skr.security");
//          intent.addCategory("com.singuloid.secphone");
        }
        return intent;
    }

    public List<String> queryLauncherPackages() {
        List<String> launchers = new ArrayList<>();
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addCategory(Intent.CATEGORY_MONKEY);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resolveInfos) {
            launchers.add(resolveInfo.activityInfo.packageName);
        }
        return launchers;
    }

    public ResolveInfo queryDefaultLauncher() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        return mPackageManager.resolveActivity(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
    }

    /**
     * 解析某些文件夹下的apk
     *
     * @param paths
     * @return
     */
    public List<PackageInfo> findAndParseAPKs(List<String> paths) {
        List<PackageInfo> packageList = new ArrayList<>();
        if (paths == null)
            return packageList;
        for (String path : paths) {
            File[] dirFiles = new File(path).listFiles();
            if (dirFiles == null)
                continue;
            for (File f : dirFiles) {
                if (!f.getName().toLowerCase().endsWith(".apk"))
                    continue;
                PackageInfo pkgInfo = null;
                try {
                    pkgInfo = mPackageManager.getPackageArchiveInfo(f.getAbsolutePath(), 0);
                    pkgInfo.applicationInfo.sourceDir = f.getAbsolutePath();
                    pkgInfo.applicationInfo.publicSourceDir = f.getAbsolutePath();
                } catch (Exception e) {
                    e.printStackTrace();
                    // Ignore
                }
                if (pkgInfo != null)
                    packageList.add(pkgInfo);
            }
        }
        return packageList;
    }

    /**
     * 判断是否是system级别的app
     * <>
     * 华为：
     * 第三方预置应用以及可卸载厂商应用存储在/data/hw_init/目录下
     * /system/app/
     * /system/priv-app/
     * /cust/all/
     * /data/hw_init/
     * /product/app
     * /system/framework
     * /system/delapp/
     * </br>
     *
     * @param packageName
     * @return
     */
    public boolean isSystemApp(String packageName) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
            if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0) {
                String sourceDir = packageInfo.applicationInfo.sourceDir;
                if (!sourceDir.startsWith("/data")) {
                    return true;
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断是否是第三方应用(即不是系统应用)
     *
     * @param packageName
     * @return
     */
    public boolean isThirdApp(String packageName) {
        try {
            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
            if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0) {
                String sourceDir = packageInfo.applicationInfo.sourceDir;
                if (!sourceDir.startsWith("/data")) {
                    return false;
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return true;
    }


    private static final String BOOT_START_PERMISSION = "android.permission.RECEIVE_BOOT_COMPLETED";

    /**
     * 　　      * 获取Android开机启动列表
     */
    public List<Map<String, Object>> getAutoLauncherApps() {
        PackageManager pm = mContext.getPackageManager();
        List<ApplicationInfo> appInfo = pm.getInstalledApplications(0);
        Iterator<ApplicationInfo> appInfoIterator = appInfo.iterator();
        List<Map<String, Object>> appList = new ArrayList<Map<String, Object>>(appInfo.size());

        while (appInfoIterator.hasNext()) {
            ApplicationInfo app = appInfoIterator.next();
            int flag = pm.checkPermission(
                    BOOT_START_PERMISSION, app.packageName);
            if (flag == PackageManager.PERMISSION_GRANTED) {
                Map<String, Object> appMap = new HashMap<String, Object>();
                String label = pm.getApplicationLabel(app).toString();
                Drawable icon = pm.getApplicationIcon(app);
                String packageName = app.packageName;
                appMap.put("label", label);
                appMap.put("icon", icon);
                appMap.put("desc", packageName);
                appList.add(appMap);
            }
        }
        return appList;
    }

    public boolean isAppInstalled(String packagename) {
        PackageInfo packageInfo;
        try {
            packageInfo = mContext.getPackageManager().getPackageInfo(packagename, 0);
        } catch (PackageManager.NameNotFoundException e) {
            packageInfo = null;
            Log.d(TAG, "isAppInstalled: " + e.toString());
        }
        if (packageInfo == null) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * <permission android:name="android.permission.FORCE_STOP_PACKAGES"  
     *  android:permissionGroup="android.permission-group.SYSTEM_TOOLS"  
     *  android:protectionLevel="signature"  
     *  android:label="@string/permlab_forceStopPackages"  
     *  android:description="@string/permdesc_forceStopPackages"/>  
     *
     * @param packageName
     */
    public void foceStopApp(String packageName) {
        try {
            ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
            Method method = Class.forName("android.app.ActivityManager").getMethod("forceStopPackage", String.class);
            method.invoke(activityManager, packageName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
