package com.android.launcher3.manager;

import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.android.launcher3.model.AppTimeConfig;
import com.android.launcher3.model.AppUseData;
import com.android.launcher3.model.TimeConfig;
import com.android.launcher3.model.TimeModel;
import com.android.launcher3.model.TimeRegion;
import com.android.launcher3.util.Logger;
import com.android.launcher3.util.PermissionUtil;
import com.android.launcher3.util.TimeConfigSaver;
import com.android.launcher3.util.TimeUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import androidx.collection.ArraySet;

public class TimeModeManager {

    private static final String TAG = "TimeModeManager";
    private UsageStatsManager usageStatsManager;
    private static TimeModeManager mInstance;
    private Context context;
    private TimeConfigSaver configSaver;
    private Map<Integer, TimeConfig> configMap;
    private long LockScreenEndTime;
    private int currentWorkModel;
    private PackageManager packageManager;
    //   退出管制 可自由使用任何app
    private boolean exitProtect = false;

    //    当天（从00:00开始）各类型的app已经使用的总时长
    private Map<Integer, Long> appTypeUseTimestamp;


    private TimeModeManager(Context context) {
        this.context = context;
        Logger.e(TAG, "TimeModeManager\t" + (context == null));
        configSaver = new TimeConfigSaver(context);
        configMap = configSaver.getConfig();
        if (configMap == null) {
            configMap = new HashMap<>();
        }
        LockScreenEndTime = configSaver.getLockScreenEndTime();

        currentWorkModel = configSaver.getCurrentWorkMode();
        appTypeUseTimestamp = new HashMap<>();
        exitProtect = configSaver.getExitState();
        packageManager = context.getPackageManager();
    }

    public static TimeModeManager getInstance(Context context) {

        if (mInstance == null) {
            synchronized (TimeModeManager.class) {
                if (mInstance == null) {
                    mInstance = new TimeModeManager(context);
                }
            }
        }

        return mInstance;
    }


    /**
     * 设置当前的工作模式
     *
     * @param model
     */
    public void setCurrentWorkModel(@ColumnDef.TimeManager.TimeMode int model) {
        currentWorkModel = model;
        configSaver.saveWorkMode(currentWorkModel);
    }


    /**
     * 添加工作模式
     *
     * @param config
     */
    public void addWorkModeConfig(TimeConfig config) {
        configMap.put(config.getWorkMode(), config);
        configSaver.save(configMap);
    }


    /**
     * 判断应用是否可以使用
     *
     * @param packageName
     * @return
     */
    public int canUse(String packageName) {
        if (TextUtils.isEmpty(packageName))
            return -1;
        ManagementInfo info = LauncherManager.getInstance().getManageAppInfo(packageName);
        TimeConfig config = configMap.get(currentWorkModel);

        if (packageName.equals(context.getPackageName()))
            return 0;

        if (info == null) {
            Logger.e(TAG, packageName + " cant found management info");
            return -1;
        }

        if (info.getUseType() == ColumnDef.AppUseType.SAFE_TYPE || info.getUseType() == ColumnDef.AppUseType.LEARN_TYPE) {

            return 0;
        }


        if (config == null) {
            Logger.e(TAG, "dont have work mode config in currentWorkmode =\t" + currentWorkModel);
            return -1;
        }


        Logger.e(TAG, packageName + "\t" + info.toString());

        if (info.getLock() != ColumnDef.LockApp.LOCKED) {
            if (includeTimeRegion(config.getRegionList())) {

                //        判断金币是否充足
                if (LauncherManager.getInstance().getCoinNum() <= 0) {

                    return -4;
                }

                long canUseTime = 0;

                // 获取某个应用类别下的使用时间
                if (currentWorkModel == ColumnDef.TimeManager.HOLIDAY_MODE) {
                    canUseTime = getUseTimeByAppType(config.getAppTimeConfigs(), info.getUseType());
                } else {
                    if (TimeUtils.isWeekend()) {
                        currentWorkModel = ColumnDef.TimeManager.WEEK_RESET;
                        canUseTime = getUseTimeByAppType(configMap.get(ColumnDef.TimeManager.WEEK_RESET).getAppTimeConfigs(), info.getUseType());
                    } else {
                        currentWorkModel = ColumnDef.TimeManager.WORK_DAY;
                        canUseTime = getUseTimeByAppType(configMap.get(ColumnDef.TimeManager.WORK_DAY).getAppTimeConfigs(), info.getUseType());
                    }
                }

                HashMap<Integer, Long> useTimestamp = getAppUseTimeStamp();

                long totalUseTimeByType = useTimestamp.get(info.getUseType());

                Logger.e(TAG, "该分类下已使用的总时长\n" + totalUseTimeByType);

                Logger.e(TAG, "该分类下可使用的总时长\n" + canUseTime);

//               金币数可以兑换的使用时长

                if (totalUseTimeByType > canUseTime) {
                    Logger.e(TAG, String.format("this class had use time %d can use time %d\t", totalUseTimeByType, canUseTime));
                    return -3;
                }

//                app自身的设置使用时长优先级更高
                if (info.getUseEndTimeStamp() > 0) {
//                    应用本身的使用时间
                    canUseTime = Math.min(canUseTime, info.getUseEndTimeStamp());
                }


                long hadUseTime = getAppUseTimeStampDay(context, packageName);
                if (canUseTime > 0 && hadUseTime > canUseTime) {
                    Logger.e(TAG, String.format("this app had use time %d  can use time %d \t", hadUseTime, canUseTime));
                    return -2;
                }
            } else {
                Logger.e(TAG, "not includeTimeRegion");
            }
        }

        return 0;
    }


    public HashMap<Integer, Long> getAppUseTimeStamp() {
        Logger.e(TAG, "getAppUseTimeStamp start\t" + System.currentTimeMillis());
        ArrayMap<String, ManagementInfo> appInfo = LauncherManager.getInstance().getAppInfo();
        HashMap<Integer, Long> timeStamp = new HashMap<>();

        HashSet<String> usedPackaged = new HashSet<>();

        List<AppUseData> data = new ArrayList<>();
        if (PermissionUtil.checkAppUsagePermission(context)) {
            UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);


//            计算当天使用过的应用
            if (usageStatsManager != null) {

                Calendar beginCal = Calendar.getInstance();
                beginCal.set(Calendar.HOUR_OF_DAY, 0);
                beginCal.set(Calendar.MINUTE, 0);
                beginCal.set(Calendar.SECOND, 0);
                Calendar endCal = Calendar.getInstance();
                UsageEvents events = usageStatsManager.queryEvents(beginCal.getTimeInMillis(), endCal.getTimeInMillis());

                Logger.e(TAG, beginCal.getTimeInMillis() + "\t" + endCal.getTimeInMillis());
                UsageEvents.Event event = new UsageEvents.Event();
                while (events.hasNextEvent()) {
                    events.getNextEvent(event);

                    if (event.getEventType() == UsageEvents.Event.MOVE_TO_BACKGROUND || event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
                        String eventPackage = event.getPackageName();

                        usedPackaged.add(eventPackage);
                    }

                }
            }
        }


        Iterator<String> iterator = usedPackaged.iterator();

        //计算当天使用过的应用 使用时长
        while (iterator.hasNext()) {
            String packageName = iterator.next();

            long useTimeStamp = getAppUseTimeStampDay(context, packageName);
            data.add(new AppUseData(packageName, useTimeStamp));
        }


        long totalUseTimeStampDaliyLearnType = 0;
        long totalUseTimeStampDaliyGameType = 0;
        long totalUseTimeStampDaliyUnclassType = 0;
        long totalUseTimeStampDaliySafeType = 0;

        if (data.size() > 0) {
            for (AppUseData useData : data) {

                long useTimestamp = useData.mUsageTime;

                ManagementInfo info = appInfo.get(useData.mPackageName);

                if (LauncherManager.getInstance().isSafePackageName(useData.mPackageName)) {
                    totalUseTimeStampDaliySafeType += useTimestamp;
                } else {
                    if (info != null) {
                        switch (info.getUseType()) {
                            case ColumnDef.AppUseType.LEARN_TYPE:
                                totalUseTimeStampDaliyLearnType += useTimestamp;
                                break;
                            case ColumnDef.AppUseType.GAME_LOCK_TYPE:
                                totalUseTimeStampDaliyGameType += useTimestamp;
                                break;
                            case ColumnDef.AppUseType.SAFE_TYPE:
                                totalUseTimeStampDaliySafeType += useTimestamp;
                                break;
                        }
                    } else {
                        totalUseTimeStampDaliyUnclassType += useTimestamp;
                    }
                }

            }

        }


        timeStamp.put(ColumnDef.AppUseType.LEARN_TYPE, totalUseTimeStampDaliyLearnType);

        timeStamp.put(ColumnDef.AppUseType.GAME_LOCK_TYPE, totalUseTimeStampDaliyGameType);

        timeStamp.put(ColumnDef.AppUseType.SAFE_TYPE, totalUseTimeStampDaliySafeType);

        timeStamp.put(ColumnDef.AppUseType.UNCLASS_TYPE, totalUseTimeStampDaliyUnclassType);

        Logger.e(TAG, JSON.toJSONString(timeStamp));
        Logger.e(TAG, "getAppUseTimeStamp end\t" + System.currentTimeMillis());
        return timeStamp;

    }

    private AppUseData containItem(List<AppUseData> items, String packageName) {
        for (AppUseData item : items) {
            if (item.mPackageName.equals(packageName)) return item;
        }
        return null;
    }

    /**
     * 获取某个app当天的已使用时长
     *
     * @param context
     * @param packageName
     * @return
     */
    private long getAppUseTimeStampDay(Context context, String packageName) {
        long totalUseTimeStampDaliy = 0;
        if (PermissionUtil.checkAppUsagePermission(context)) {
            UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);


            Calendar beginCal = Calendar.getInstance();
            beginCal.set(Calendar.HOUR_OF_DAY, 0);
            beginCal.set(Calendar.MINUTE, 0);
            beginCal.set(Calendar.SECOND, 0);
            Calendar endCal = Calendar.getInstance();
            UsageEvents events = usageStatsManager.queryEvents(beginCal.getTimeInMillis(), endCal.getTimeInMillis());
            UsageEvents.Event event = new UsageEvents.Event();

            long startTime = beginCal.getTimeInMillis();
            boolean isForegounding = false;
            while (events.hasNextEvent()) {

                events.getNextEvent(event);
                int eventType = event.getEventType();
                long eventTime = event.getTimeStamp();
                String eventPackage = event.getPackageName();

                if (eventPackage.equals(packageName)) {
                    if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {

                        startTime = eventTime;
                        isForegounding = true;
                    }

                    if (eventType == UsageEvents.Event.MOVE_TO_BACKGROUND) {
                        isForegounding = false;
                        totalUseTimeStampDaliy += eventTime - startTime;
                    }

                }

            }

            if (isForegounding) {
                totalUseTimeStampDaliy += System.currentTimeMillis() - startTime;
            }

        }

        return totalUseTimeStampDaliy / 1000;
    }

    /**
     * 判断当前时间是否在选中的时间范围内
     *
     * @param regionList
     * @return
     */
    public boolean includeTimeRegion(List<TimeRegion> regionList) {

        if (regionList == null)
            return false;
        if (regionList.isEmpty())
            return false;

        long time = (System.currentTimeMillis() - TimeUtils.getTimeZeroClock()) / 1000;
        for (TimeRegion region : regionList) {
            if (region.containTime(time)) {
                return true;
            }
        }

        return false;
    }

    public long getUseTimeByAppType(List<AppTimeConfig> timeConfigs, @ColumnDef.AppUseType.UseTypeMode int appType) {

        if (timeConfigs == null)
            return 0;

        for (AppTimeConfig timeConfig : timeConfigs) {
            if (timeConfig.appType == appType) {
                return timeConfig.appUseTimeSecond;
            }
        }

        return 0;
    }


    public TimeConfig getTimeConfig(@ColumnDef.TimeManager.TimeMode int mode) {
        Logger.e(TAG, "getTimeConfig" + mode);
        if (configMap != null) {
            return configMap.get(mode);
        }
        return null;
    }

    /**
     * 当前工作模式下配置的锁屏模式
     *
     * @return
     */
    public int getCurrentScreenModel() {
        TimeConfig config = configMap.get(currentWorkModel);
        Logger.e(TAG, currentWorkModel + "\tgetCurrentScreenModel\t" + JSON.toJSONString(configMap));
        if (config == null || config.getRegionList() == null) {
            Logger.e(TAG, "getCurrentScreenModel null");
            return ColumnDef.LockScreen.MODE_UNLOCK;
        }

        if (includeTimeRegion(config.getRegionList())) {
//            在可用的时间段内
            return ColumnDef.LockScreen.MODE_UNLOCK;
        }
        return config.getLockScreenMode();
    }


    public int getCurrentWorkModel() {
        return currentWorkModel;
    }


    public void updateLockScreenEndTime(long timeStamp) {
        LockScreenEndTime = timeStamp;
        configSaver.updateLockScreenEndTime(timeStamp);
        configSaver.updateLockScreenType(ColumnDef.LockScreen.MODE_FORCE_LOCK);
    }


    public boolean inTimeRegionTolockScreen() {
        TimeConfig config = configMap.get(currentWorkModel);

        if (config == null)
            return true;

        return includeTimeRegion(config.getRegionList());

    }

    public long getLockScreenEndTime() {
        return LockScreenEndTime;
    }


    public void updateLockScreenType(@ColumnDef.LockScreen.LockScreenMode int lockScreenMode) {
        configSaver.updateLockScreenType(lockScreenMode);
    }


    /**
     * 家长端临时锁屏的模式
     *
     * @return
     */
    public int getLockScreenType() {
        return configSaver.getLockScreenType();
    }


    public boolean isExitProtect() {
        return exitProtect;
    }

    public synchronized void setExitProtect(boolean exit) {
        configSaver.putExitState(exit);
        exitProtect = exit;
    }

    public void updateUninstallEnabled(boolean enabled) {
        configSaver.putUninstallEnable(enabled);
    }

    public boolean getUninstallEnable() {
        return configSaver.getUninstallEnable();
    }

    public void putUseTimeByAppType(@ColumnDef.AppUseType.UseTypeMode int type, long totalTimeStamp) {
        appTypeUseTimestamp.put(type, totalTimeStamp);
    }

    class ClonedEvent {

        String packageName;
        String eventClass;
        long timeStamp;
        int eventType;


        ClonedEvent(UsageEvents.Event event) {
            packageName = event.getPackageName();
            eventClass = event.getClassName();
            timeStamp = event.getTimeStamp();
            eventType = event.getEventType();
        }

        public ClonedEvent() {
        }

        @Override
        public String toString() {
            return "ClonedEvent{" +
                    "packageName='" + packageName + '\'' +
                    ", eventClass='" + eventClass + '\'' +
                    ", timeStamp=" + timeStamp +
                    ", eventType=" + eventType +
                    '}';
        }
    }
}
