package cn.liujson.app.update;

import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;


import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import java.io.File;
import java.util.List;
import java.util.Objects;

import cn.liujson.app.update.listener.OnProgressListener;
import cn.liujson.app.update.service.ApkDownloadService;
import cn.liujson.app.update.util.Log;

/**
 * @author liujson
 * @date 2020/8/3.
 */
public class AppUpdateManager {

    private final static int REQ_CODE_INSTALL_APP = 0x10;

    public final String sourceUrl;
    public final String destPath;
    public final boolean showNotification;
    public final OnProgressListener onProgressListener;
    public final boolean autoInstall;
    public final PendingIntent notifyIntent;


    private AppUpdateManager(Builder builder) {
        this.sourceUrl = builder.sourceUrl;
        this.destPath = builder.destPath;
        this.showNotification = builder.showNotification;
        this.onProgressListener = builder.onProgressListener;
        this.autoInstall = builder.autoInstall;
        this.notifyIntent = builder.notifyIntent;
    }

    @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
    public void download(final Context context) {
        //1. 监测路径下有没有已经下载好的安装包
        if (Utils.isNeedUpdate(context, Utils.getApkVersionCode(context, destPath))) {
            //存在新的更新包
            if (autoInstall) {
                install(context);
            }
        } else {
            //需要下载
            ApkDownloadService.bindService(context.getApplicationContext(), new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    ApkDownloadService.ApkDownloadBinder apkDownloadBinder = (ApkDownloadService.ApkDownloadBinder) service;
                    apkDownloadBinder.start(AppUpdateManager.this);
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {

                }
            });
        }
    }

    @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
    public void install(Context context) {
        //检查包是否正常
        if (Utils.getApkVersionCode(context, destPath) == -1) {
            Log.e("install--> path:" + destPath + " is not a apk file");
            return;
        }
        File apkFile = new File(destPath);
        Utils.installApp(context, apkFile);
    }

    @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
    public void install(Activity activity) {
        //检查包是否正常
        if (Utils.getApkVersionCode(activity, destPath) == -1) {
            Log.e("install--> path:" + destPath + " is not a apk file");
            return;
        }
        File apkFile = new File(destPath);
        Utils.installApp(activity, apkFile);
    }

    //region AppUpdateManager Builder

    public static class Builder {
        /**
         * apk file url
         */
        String sourceUrl;
        /**
         * 下载路径
         */
        String destPath;

        /**
         * 是否显示通知栏
         */
        boolean showNotification = true;

        /**
         * 下载进度监听器
         */
        OnProgressListener onProgressListener;

        /**
         * 下载后完成后自动安装
         */
        boolean autoInstall = true;

        /**
         * 点击通知的 PendingIntent
         */
        PendingIntent notifyIntent;

        /**
         * 后台下载
         *
         * @param sourceUrl
         * @return
         */
        public Builder sourceUrl(String sourceUrl) {
            Objects.requireNonNull(sourceUrl, "sourceUrl can not be null");
            this.sourceUrl = sourceUrl;
            return this;
        }

        public Builder destPath(String destPath) {
            Objects.requireNonNull(destPath, "destPath can not be null");
            this.destPath = destPath;
            return this;
        }

        public Builder showNotification(boolean showNotification) {
            this.showNotification = showNotification;
            return this;
        }

        public Builder onProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
            return this;
        }

        public Builder autoInstall(boolean autoInstall) {
            this.autoInstall = autoInstall;
            return this;
        }

        public Builder notifyIntent(PendingIntent notifyIntent) {
            this.notifyIntent = notifyIntent;
            return this;
        }

        public AppUpdateManager build() {
            return new AppUpdateManager(this);
        }


    }
    //endregion

    //region app更新相关工具类

    /**
     * app更新相关工具类
     */
    public static class Utils {

        private Utils() {
            //通过私有构造器抛异常，强化不可实例化的能力
            throw new AssertionError();
        }

        /**
         * 获取本应用的 VersionName
         *
         * @param context
         * @return 如果能获取到返回versionName，否则返回空字符串
         */
        public static String getAppVersionName(Context context) {
            try {
                PackageManager pm = context.getPackageManager();
                PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
                return pi.versionName;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return "";
        }

        /**
         * 获取本应用的 versionCode
         *
         * @param context
         * @return
         */
        public static long getAppVersionCode(Context context) {
            PackageInfo packageInfo = getAppPackageInfo(context);
            if (packageInfo != null) {
                //得到版本信息
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    return packageInfo.getLongVersionCode();
                }
                //noinspection deprecation
                return packageInfo.versionCode;
            }
            return -1;
        }

        /**
         * 检查是否需要更新
         *
         * @param context    上下文
         * @param newVersion 新版本versionCode
         * @return 如果需要更新返回true，否则返回false
         */
        public static boolean isNeedUpdate(Context context, long newVersion) {
            long appVersionCode = getAppVersionCode(context);
            return appVersionCode != -1 && newVersion > appVersionCode;
        }

        /**
         * 获取apk版本信息
         *
         * @param context
         * @param apkPath
         * @return
         */
        public static long getApkVersionCode(Context context, String apkPath) {
            PackageInfo packageInfo = getPackageInfo(context, apkPath);
            if (packageInfo != null) {
                //得到版本信息
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    return packageInfo.getLongVersionCode();
                }
                //noinspection deprecation
                return packageInfo.versionCode;
            }
            return -1;
        }

        /**
         * 获取apk版本信息
         *
         * @param context
         * @param
         * @return
         */
        public static long getApkVersionCode(Context context, File apkFile) {
            return getApkVersionCode(context, apkFile.getAbsolutePath());
        }

        @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
        public static void installApp(Activity activity, File appFile) {
            try {
                Intent intent = getInstallAppIntent(activity, appFile);
                if (activity.getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
                    activity.startActivityForResult(intent, REQ_CODE_INSTALL_APP);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
        public static void installApp(Context context, File appFile) {
            try {
                Intent intent = getInstallAppIntent(context, appFile);
                if (context.getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
                    context.startActivity(intent);
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e("installApp-> error message:" + e.getMessage());
            }
        }

        /**
         * 获取安装 Intent
         *
         * @param context
         * @param appFile
         * @return
         */
        @RequiresPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)
        public static Intent getInstallAppIntent(Context context, File appFile) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //是否有安装权限
                if (!context.getPackageManager().canRequestPackageInstalls()) {
                    Log.e("Create install App Intent failed , permission denied. action is ACTION_MANAGE_UNKNOWN_APP_SOURCES");
                    return null;
                }
            }
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //区别于 FLAG_GRANT_READ_URI_PERMISSION 跟 FLAG_GRANT_WRITE_URI_PERMISSION， URI权限会持久存在即使重启，直到明确的用 revokeUriPermission(Uri, int) 撤销。 这个flag只提供可能持久授权。但是接收的应用必须调用ContentResolver的takePersistableUriPermission(Uri, int)方法实现
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
                Uri fileUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", appFile);
                intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
            } else {
                intent.setDataAndType(Uri.fromFile(appFile), "application/vnd.android.package-archive");
            }
            return intent;
        }

        /**
         * 判断应用是否在前台
         *
         * @param context 上下文
         * @return
         */
        public static boolean isAppOnForeground(Context context) {

            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            String packageName = context.getPackageName();

            List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
            if (appProcesses == null) {
                return false;
            }


            for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {

                if (appProcess.processName.equals(packageName) && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    return true;
                }
            }

            return false;
        }

        /**
         * 判断服务是否运行
         */
        private boolean isServiceRunning(final Context context, final String className) {
            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.RunningServiceInfo> info = activityManager.getRunningServices(Integer.MAX_VALUE);
            if (info == null || info.size() == 0) {
                return false;
            }
            for (ActivityManager.RunningServiceInfo aInfo : info) {
                if (className.equals(aInfo.service.getClassName())) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 检查安装未知来源应用权限
         */
        public static boolean checkInstallUnknownAppSources(Context context){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //是否有安装权限
                if (!getPackageManager(context).canRequestPackageInstalls()) {
                    new AlertDialog.Builder(context)
                            .setTitle("温馨提示").setMessage("您的应用需要安装外部来源应用权限！")
                            .setPositiveButton("立即开启", (d, i) -> {
                                Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()));
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                ContextCompat.startActivity(context, intent, null);
                            })
                            .setNegativeButton("取消", null)
                            .show();
                    return false;
                }
            }
            return true;
        }


        public static PackageInfo getPackageInfo(Context context, @NonNull String archiveFilePath) {
            return getPackageManager(context).getPackageArchiveInfo(archiveFilePath, PackageManager.GET_ACTIVITIES);
        }

        private static PackageManager getPackageManager(Context context) {
            return context.getPackageManager();
        }

        private static PackageInfo getAppPackageInfo(Context context) {
            try {
                return getPackageManager(context).getPackageInfo(context.getPackageName(), 0);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }



    }
    //endregion
}
