package cn.liujson.app.update.service;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import java.util.ArrayList;
import java.util.List;

import app.update.rxhttp.RxHttp;
import cn.liujson.app.update.AppUpdateManager;
import cn.liujson.app.update.R;
import cn.liujson.app.update.listener.OnProgressListener;
import cn.liujson.app.update.util.Log;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

/**
 * Apk Download Service
 *
 * @author liujson
 * @date 2020/8/4.
 */
public class ApkDownloadService extends Service implements OnProgressListener {

    private static final String CHANNEL_ID = "cn.liujson.app.update.channel.id";
    private static final int NOTIFY_ID = 0x51;
    private static final CharSequence NOTIFICATION_CHANNEL_NAME = "app update notification channel";
    private static final String NOTIFICATION_CHANNEL_DESCRIPTION = "about app update download ...";

    private static final String TAG = "ApkDownloadService";

    private ApkDownloadBinder mBinder;

    private List<OnProgressListener> onProgressListenerList = new ArrayList<>();

    private List<Disposable> rxDisposableList = new ArrayList<>();

    private NotificationCompat.Builder notificationBuilder;

    private NotificationManager mNotificationManager;

    private boolean isDownloadRunning = false;

    private AppUpdateManager mAppUpdateManager;

    /**
     * 绑定并启动服务
     *
     * @param context
     * @param connection
     */
    public static void bindService(Context context, ServiceConnection connection) {
        Intent intent = new Intent(context, ApkDownloadService.class);
        //后台启动
        context.startService(intent);
        //绑定启动
        context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    /**
     * 服务解绑
     *
     * @param context
     * @param connection
     */
    public static void unbindService(Context context, ServiceConnection connection) {
        context.unbindService(connection);
    }

    @Override
    public void onCreate() {
        super.onCreate();

        initNotification();
        mBinder = new ApkDownloadBinder();
    }

    /**
     * 初始化通知
     */
    private void initNotification() {
        mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE);
        //创建渠道
        createNotificationChannel();

        notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
        notificationBuilder.setContentTitle("App Download")
                .setContentText("Download in progress")
                .setSmallIcon(R.drawable.ic_apk_download)
                .setOngoing(true)
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_LOW);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        for (Disposable disposable : rxDisposableList) {
            disposable.dispose();
        }
        rxDisposableList.clear();
        mNotificationManager.cancel(NOTIFY_ID);
    }

    /**
     * 开始一个下载任务
     *
     * @param sourceUrl 资源Url
     * @param destPath  要下载到的保存路径
     */
    private void download(final String sourceUrl, final String destPath) {
        Disposable disposable = RxHttp.get(sourceUrl)
                .asDownload(destPath, progress -> {
                    //上传进度回调,0-100，仅在进度有更新时才会回调
                    int currentProgress = progress.getProgress(); //当前进度 0-100
//                    long currentSize = progress.getCurrentSize(); //当前已上传的字节大小
//                    long totalSize = progress.getTotalSize();     //要上传的总字节大小
                    this.onProgress(currentProgress, 100);
                }, AndroidSchedulers.mainThread())
                .subscribe(this::onFinish, this::onError);
        isDownloadRunning = true;
        rxDisposableList.add(disposable);
    }


    @Override
    public void onProgress(int progress, int maxProgress) {
        //下载进度回调,0-100，仅在进度有更新时才会回调，最多回调101次，最后一次回调文件存储路径。
        Log.d(TAG, "onProgress: progress=" + progress + "----maxProgress=" + maxProgress);
        notificationBuilder.setContentText(progress + "%");
        notificationBuilder.setOngoing(true);
        notificationBuilder.setProgress(maxProgress, progress, false);
        mNotificationManager.notify(NOTIFY_ID, notificationBuilder.build());
        for (OnProgressListener onProgressListener : onProgressListenerList) {
            onProgressListener.onProgress(progress, maxProgress);
        }
    }

    @Override
    public void onFinish(String savePath) {
        isDownloadRunning = false;
        Log.d(TAG, "download finish path: " + savePath);
        notificationBuilder.setProgress(0, 0, false);
        notificationBuilder.setContentText("Download complete");
        notificationBuilder.setOngoing(false);
        mNotificationManager.notify(NOTIFY_ID, notificationBuilder.build());
        for (OnProgressListener onProgressListener : onProgressListenerList) {
            onProgressListener.onFinish(savePath);
        }
        //完成后自动安装
        if (mAppUpdateManager != null && mAppUpdateManager.autoInstall) {
            mAppUpdateManager.install(this);
        }
        closeService();
    }

    @Override
    public void onError(Throwable throwable) {
        isDownloadRunning = false;
        Log.d(TAG, "onError: " + throwable.getMessage());
        notificationBuilder.setProgress(0, 0, false);
        notificationBuilder.setContentText("Download failed");
        notificationBuilder.setOngoing(false);
        mNotificationManager.notify(NOTIFY_ID, notificationBuilder.build());
        for (OnProgressListener onProgressListener : onProgressListenerList) {
            onProgressListener.onError(throwable);
        }
        closeService();
    }


    public void closeService() {
        stopSelf();
    }


    public class ApkDownloadBinder extends Binder {

        public void addOnProgressListener(OnProgressListener onProgressListener) {
            onProgressListenerList.add(onProgressListener);
        }

        public void removeOnProgressListener(OnProgressListener onProgressListener) {
            onProgressListenerList.remove(onProgressListener);
        }

        public boolean start(AppUpdateManager appUpdateManager) {
            addOnProgressListener(appUpdateManager.onProgressListener);
            if (isDownloadRunning) {
                Log.d(TAG, "download: isDownloadRunning = true");
                return false;
            }
            download(appUpdateManager.sourceUrl, appUpdateManager.destPath);
            mAppUpdateManager = appUpdateManager;
            if (notificationBuilder != null) {
                if (appUpdateManager.notifyIntent != null) {
                    notificationBuilder.setContentIntent(appUpdateManager.notifyIntent);
                }
            }
            return true;
        }

        public void stop() {
            closeService();
        }

    }

    /**
     * 创建通知渠道，多次调用是合法的，不会多次执行
     */
    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = NOTIFICATION_CHANNEL_NAME;
            String description = NOTIFICATION_CHANNEL_DESCRIPTION;
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}
