package com.gh.ndownload;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.text.TextUtils;

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

import com.blankj.utilcode.util.ThreadUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.ndownload.suspendwindow.NDownloadDrawOverlayPermissionWindowController;
import com.gh.ndownload.suspendwindow.NDownloadSuspendWindowController;
import com.gh.ndownload.suspendwindow.utils.NDownloadSuspendWindowHelper;
import com.lightgame.BuildConfig;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadDao;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.ForegroundNotificationManager;
import com.lightgame.utils.Utils;

import java.util.ArrayList;
import java.util.Random;

public class NDownloadService extends Service {

    public static final String KEY_SERVICE_ACTION = "service_action";
    public static final String START_FOREGROUND = "start_foreground";

    public static final String ACTION_SHOW_SUSPEND_WINDOW = "action_show_suspend_window";

    private static final String SERVICE_CHANNEL_ID = "Halo_Download";

    private static NDownloadService sService = null;

    private ForegroundNotificationManager mForegroundNotificationManager;

    private NDownloadSuspendWindowController mDownloadSuspendWindowController;

    private NDownloadDrawOverlayPermissionWindowController mDrawOverlayPermissionWindowController;

    @Nullable
    public static NDownloadService getService() {
        return sService;
    }

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

        sService = this;

        mForegroundNotificationManager = new ForegroundNotificationManager(this, this.getApplication());

        Utils.log(NDownloadService.class.getSimpleName(), "onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Utils.log(NDownloadService.class.getSimpleName(), "onStartCommand");

        int randomNotificationId = getNextIntExcludeZero();

        if (intent != null && intent.getExtras() != null) {
            String serviceAction = intent.getStringExtra(KEY_SERVICE_ACTION);

            if (START_FOREGROUND.equals(serviceAction)) {
                startForegroundIfNeeded(randomNotificationId);
            } else if (ACTION_SHOW_SUSPEND_WINDOW.equals(serviceAction)) {
                DownloadEntity entry = (DownloadEntity) intent.getSerializableExtra(DownloadConfig.KEY_DOWNLOAD_ENTRY);
                showDownloadSuspendWindowIfNeeded(entry);
                return START_NOT_STICKY;
            }

            String statusString = intent.getStringExtra(DownloadConfig.KEY_DOWNLOAD_ACTION);
            if (!TextUtils.isEmpty(statusString)) {
                // 看不懂的操作
                DownloadStatus status = DownloadStatus.valueOf(statusString);
                DownloadEntity entry = (DownloadEntity) intent.getSerializableExtra(DownloadConfig.KEY_DOWNLOAD_ENTRY);
                DownloadEntity downloadEntity = DownloadDao.getInstance(this).get(entry.getUrl());
                if (downloadEntity == null) {
                    // 设置开始下载时间(排序用到)
                    entry.setStart(System.currentTimeMillis());
                }

                // 置换最新状态
                entry.setStatus(status);

                // 删除下载错误信息
                entry.setError("");
                DownloadDao.getInstance(this).removeErrorMessage(entry.getUrl());

                if (BuildConfig.DEBUG) {
                    Utils.log(NDownloadService.class.getSimpleName(), entry.getPackageName() + "==>" + entry.getStatus().getStatus());
                }
                switch (status) {
                    case subscribe:
                        subscribeDownload(entry);
                        break;
                    case add:
                        addDownload(entry);
                        break;
                    case pause:
                    case timeout:
                    case neterror:
                    case diskioerror:
                    case diskisfull:
                        pauseDownload(entry);
                        break;
                    case resume:
                        resumeDownload(entry);
                        break;
                    case cancel:
                        cancelDownload(entry);
                        break;
                    default:
                        if (BuildConfig.DEBUG) {
                            Utils.log(NDownloadService.class.getSimpleName(), "无法处理的下载状态:" + entry.getStatus().getStatus());
                        }
                        break;
                }
            } else {
                if (BuildConfig.DEBUG) {
                    Utils.log(NDownloadService.class.getSimpleName(), "启动了一个空的下载服务");
                }
            }
        } else {
            // 无参时也默认以前台启动
            startForegroundIfNeeded(randomNotificationId);
        }

        stopForegroundIfNeeded(randomNotificationId);

        // 不需要 intent 为空的重建
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        sService = null;

        if (mDownloadSuspendWindowController != null) {
            mDownloadSuspendWindowController.dismiss();
        }

        if (mDrawOverlayPermissionWindowController != null) {
            mDrawOverlayPermissionWindowController.dismiss();
        }
    }

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

    synchronized void subscribeDownload(DownloadEntity entry) {
        DownloadDao.getInstance(this).newOrUpdate(entry);
        NDataChanger.INSTANCE.notifyDataChanged(entry);
        DownloadManager.getInstance().onTaskAdded(entry);
    }

    synchronized void addDownload(DownloadEntity entry) {
        if (NDataChanger.INSTANCE.getDownloadingTaskUrlSet().size() >= DownloadConfig.MAX_DOWNLOADING_SIZE) {
            // 1.改任务队列的状态
            entry.setStatus(DownloadStatus.waiting);
            // 2.改数据库状态
            DownloadDao.getInstance(this).newOrUpdate(entry);
            // 3.通知更新
            NDataChanger.INSTANCE.notifyDataChanged(entry);
        } else {
            startDownload(entry);
        }
        DownloadManager.getInstance().onTaskAdded(entry);
    }

    synchronized void pauseDownload(DownloadEntity entry) {
        if (entry != null) {
            entry.setStatus(DownloadStatus.pause);

            // 1.改任务队列的状态
            NDownloadBridge.INSTANCE.pause(entry.getUrl());
            NDataChanger.INSTANCE.pauseDownloadingTask(entry.getUrl());

            // 2.改数据库状态
            DownloadDao.getInstance(this).update(entry, false);
        }
    }

    synchronized void resumeDownload(DownloadEntity entry) {
        addDownload(entry);
    }

    synchronized void cancelDownload(DownloadEntity downloadEntity) {
        if (NDataChanger.INSTANCE.getDownloadingTaskUrlSet().contains(downloadEntity.getUrl())) {
            NDownloadBridge.INSTANCE.cancel(downloadEntity.getUrl());
            // 改任务队列的状态
            NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(downloadEntity.getUrl());
            NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
        }
        NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
        DownloadManager.getInstance().onTaskCancelled(downloadEntity);
    }

    synchronized void startDownload(DownloadEntity entry) {
        if (!NDataChanger.INSTANCE.getDownloadingTaskUrlSet().contains(entry.getUrl())) {
            // 显示下载悬浮窗
            showDownloadSuspendWindowIfNeeded(entry);

            // 刷新初始状态
            NDataChanger.INSTANCE.notifyDataChanged(entry);

            entry.getMeta().put(DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY, entry.getStatus().getStatus());
            // 1.改任务队列的状态
            entry.setStatus(DownloadStatus.downloading);
            NDataChanger.INSTANCE.getDownloadingTaskUrlSet().add(entry.getUrl());

            // 2.改数据库状态
            DownloadDao.getInstance(this).newOrUpdate(entry);

            // 3.执行下载
            NDownloadBridge.INSTANCE.download(entry);

            // 4.通知更新
            NDataChanger.INSTANCE.notifyDataChanged(entry);
        } else {
            Utils.log("Fuck this, we received multiple download request for the same url");
        }
    }

    /**
     * 找到下一个处于 waiting 状态的任务继续
     * @param url 需要移除的 url 对应的数据
     */
    public synchronized void removeFromDataChangerAndResumeWaitingTask(String url) {
        NDataChanger.INSTANCE.getDownloadingTaskUrlSet().remove(url);
        ArrayList<DownloadEntity> downloadEntitySnapshotList = DownloadManager.getInstance().getAllDownloadEntitySnapshots();
        for (DownloadEntity entry : downloadEntitySnapshotList) {
            if (DownloadStatus.waiting.equals(entry.getStatus())) {
                // 刷新状态(从等待中到开始下载,状态应该变为继续下载)
                entry.setStatus(DownloadStatus.resume);
                startDownload(entry);

                if (BuildConfig.DEBUG) {
                    Utils.log(NDownloadService.class.getSimpleName(), entry.getPackageName() + "==>" + entry.getStatus().getStatus());
                }
                return;
            }
        }
    }

    private void startForegroundIfNeeded(int notificationId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(SERVICE_CHANNEL_ID, "Halo Download", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
            Notification notification = new NotificationCompat.Builder(this, SERVICE_CHANNEL_ID)
                    .setSmallIcon(com.lightgame.R.drawable.ic_download_notification)
                    .build();

            if (mForegroundNotificationManager != null) {
                mForegroundNotificationManager.notify(notificationId, notification);
            }
        }
    }

    private void stopForegroundIfNeeded(int notificationId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mForegroundNotificationManager != null) {
                mForegroundNotificationManager.cancel(notificationId);
            }
        }
    }

    private void showDownloadSuspendWindowIfNeeded(DownloadEntity entry) {
        if (ThreadUtils.isMainThread()) {
            showDownloadSuspendWindowIfNeededInner(entry);
        } else {
            AppExecutor.getUiExecutor().execute(() -> showDownloadSuspendWindowIfNeededInner(entry));
        }
    }

    private void showDownloadSuspendWindowIfNeededInner(DownloadEntity entry) {
        if (!NDownloadSuspendWindowHelper.shouldSkipDownloadEntity(getApplicationContext(), entry)) {
            if (NDownloadSuspendWindowHelper.canDrawOverLayer(getApplicationContext())) {// 已开启悬浮窗权限，直接显示悬浮窗
                showDownloadSuspendWindow();
            } else {// 未开启悬浮窗权限，显示开启悬浮窗权限引导窗口
                Activity topActivity = GlobalActivityManager.INSTANCE.getCurrentActivity();
                if (!NDownloadSuspendWindowHelper.isDrawOverlayPermissionWindowShown()
                        && topActivity != null && !(topActivity instanceof SplashScreenActivity)) {
                    showDownloadDrawOverlayPermissionWindow(topActivity, entry);
                }
            }
        }
    }

    /**
     * 获取 0 以外的随机 int 数值
     */
    private int getNextIntExcludeZero() {
        int randomNumber = new Random().nextInt();
        if (randomNumber != 0) {
            return randomNumber;
        } else {
            return getNextIntExcludeZero();
        }
    }

    private void showDownloadSuspendWindow() {
        if (mDownloadSuspendWindowController == null) {
            mDownloadSuspendWindowController = new NDownloadSuspendWindowController(getApplication());
        }
        mDownloadSuspendWindowController.show();
    }

    private void showDownloadDrawOverlayPermissionWindow(Activity activity, DownloadEntity downloadEntity) {
        if (mDrawOverlayPermissionWindowController == null) {
            mDrawOverlayPermissionWindowController = new NDownloadDrawOverlayPermissionWindowController(getApplication());
            mDrawOverlayPermissionWindowController.setOnGrantDrawOverlayPermissionListener(this::showDownloadSuspendWindow);
        }
        mDrawOverlayPermissionWindowController.setCurrentDownloadEntity(downloadEntity);
        mDrawOverlayPermissionWindowController.show(activity);
        NDownloadSuspendWindowHelper.markDrawOverlayPermissionWindowShown();
    }

}
