package com.gh.ndownload;

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.gh.download.DownloadManager;
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.DownloadTask;
import com.lightgame.download.ForegroundNotificationManager;
import com.lightgame.utils.Utils;

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";
    private static final String SERVICE_CHANNEL_ID = "Halo_Download";

    private static NDownloadService sService = null;

    private ForegroundNotificationManager mForegroundNotificationManager;

    @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);
            }

            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;
    }

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

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

    synchronized void addDownload(DownloadEntity entry) {
        if (NDataChanger.INSTANCE.getDownloadingTasks().size() >= DownloadConfig.MAX_DOWNLOADING_SIZE) {
            // 1.改任务队列的状态
            entry.setStatus(DownloadStatus.waiting);
            NDataChanger.INSTANCE.getDownloadEntries().put(entry.getUrl(), entry);
            // 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) {
        DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks()
                .get(downloadEntity.getUrl());
        if (task != null) {
            NDownloadBridge.INSTANCE.cancel(downloadEntity.getUrl());
            // 改任务队列的状态
            NDataChanger.INSTANCE.getDownloadingTasks().remove(downloadEntity.getUrl());
            NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
        }
        NDataChanger.INSTANCE.getDownloadEntries().remove(downloadEntity.getUrl());
        NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
        DownloadManager.getInstance().onTaskCancelled(downloadEntity);
    }

    synchronized void startDownload(DownloadEntity entry) {
        DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
        if (task == null) {
            // 刷新初始状态
            NDataChanger.INSTANCE.notifyDataChanged(entry);

            entry.getMeta().put(DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY, entry.getStatus().getStatus());
            // 1.改任务队列的状态
            entry.setStatus(DownloadStatus.downloading);
            NDataChanger.INSTANCE.getDownloadEntries().put(entry.getUrl(), entry);
            NDataChanger.INSTANCE.getDownloadingTasks().put(entry.getUrl(), new DownloadTask(null, entry, this));

            // 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");
        }
    }

    /**
     * 从 DataChanger 里移除掉数据，并找到下一个处于 waiting 状态的任务继续
     * @param downloadEntity 需要移除的数据
     * @param removeCompletely 是否完全移除，false 时只从下载中 hashMap 移除
     */
    public synchronized void removeFromDataChangerAndResumeWaitingTask(DownloadEntity downloadEntity, boolean removeCompletely) {
        NDataChanger.INSTANCE.getDownloadingTasks().remove(downloadEntity.getUrl());
        if (removeCompletely) {
            NDataChanger.INSTANCE.getDownloadEntries().remove(downloadEntity.getUrl());
        }
        for (DownloadEntity entry : NDataChanger.INSTANCE.getDownloadEntries().values()) {
            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);
            }
        }
    }

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

}
