package com.reyun.saas.mob.user.task;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.reyun.saas.common.util.DingDingSendMsgUtil;
import com.reyun.saas.common.util.RedisUtils;
import com.reyun.saas.mob.user.dao.SdkPolicyMapper;
import com.reyun.saas.mob.util.DDBUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author: hanzepeng
 * @Date: 2021/10/27/18:06
 * @Description: 将sdk配置的策略同步到实时的ddb的表中
 */
@Slf4j
@Component
public class SyncSdkPolicyTask {


    //yy_strategy_config_android 与 yy_strategy_config_ios的主键名称
    private static final String SDK_POLICY_PRImMARY_KEY = "config_key";

    //策略总开关 关键字
    private static final String ALL_STARTEGY = "all_strategy";

    //sdk版本与策略对应关系 关键字
    private static final String SDK_VERSION_STARTEGY = "sdk_version_strategy";

    //屏幕策略关键字
    private static final String SCREEN_CONFIG = "screen_config";

    //电池策略关键字
    private static final String BATTARY_CONFIG = "battary_config";

    //应用列表配置关键字
    private static final String APPS_CONFIG = "apps_config";

    //摄像头策略关键字
    private static final String CAMERA_CONFIG = "camera_config";

    //环境变量关键字
    private static final String ENV_CONFIG = "env_config";

    //内存与磁盘关键字
    private static final String MEM_CONFIG = "mem_config";

    //badApp关键字
    private static final String BAD_APP_CONFIG = "bad_app_config";

    //badAcc关键字
    private static final String BAD_ACC_CONFIG = "auxiliaryfunction_backlist";

    //badWifi关键字
    private static final String BAD_WIFI_CONFIG = "bad_wifi_config";

    //ios 205策略关键字
    private static final String IOS_205_CONFIG = "ios_205_config";



    @Resource
    private RedisUtils redisUtils;

    @Resource
    private DDBUtils ddbUtils;

    @Resource
    private SdkPolicyMapper sdkPolicyMapper;

    @Value("${spring.profiles.active}")
    private String env;


//    @Async
//    @Scheduled(cron = "0 0/5 * * * ?")//生产环境
//    @Scheduled(cron = "0 * * * * ?")//开发测试
    public void SyncSdkPolicy() {
        //分布式锁
        if (!redisUtils.tryLock("SyncSdkPolicy", 10)) {
            log.info("另一台服务正在同步SDK策略.......");
            return;
        }


        long start = System.currentTimeMillis();
        long end = 0L;

        DingDingSendMsgUtil dingDingSendMsgUtil
                = new DingDingSendMsgUtil(DingDingSendMsgUtil.TOKEN_EXCEPTION_PUSH_MSG, DingDingSendMsgUtil.KEY_EXCEPTION_PUSH_MSG);
        try {
            //同步Android sdk版本与策略对应关系
            Map<String,List<String>> androidSdkVersionPolicy = syncAndroidSdkVersionPolicy();
            //同步Android 策略总开关
            Map<String, Integer> androidSdkPolicyConfigConfig = syncAndroidSdkPolicyConfig();
            //同步Android 分辨率策略
            Map<String,List<String>> androidScreenPolicyCount = syncAndroidScreenPolicy();
            //同步Android 电池策略
            Map<String, String> androidBattaryPolicyCount = syncAndroidBattaryPolicy();
            //同步Android 应用列表策略
            Map<String, String> androidAppsPolicyCount = syncAndroidAppsPolicy();
            //同步Android 摄像头策略
            Map<String,List<String>> androidCameraPolicyCount = syncAndroidCameraPolicy();
            //同步Android 环境变量策略
            Map<String, String> androidEnvPolicyCount = syncAndroidEnvPolicy();
            //同步Android 内存加磁盘策略
            Map<String, String> androidMemPolicyCount = syncAndroidMemPolicy();
            //同步Android 异常app包名策略
            List<String> androidSyncBadAppsCount = syncAndroidBadAppsPolicy();
            //同步Android 异常辅助功能app包名
            List<String> androidSyncBadAccCount = syncAndroidBadAccPolicy();
            //同步Android 异常wifi策略
            List<String> androidSyncBadWifiCount = syncAndroidBadWifiPolicy();
            //同步安卓标签
            Map<String, Object> androidTarConfigCount = syncAndroidTagConfig();

            //同步IOS Sdk版本与策略关系
            Map<String,List<String>> iosSdkVersionPolicy = syncIosSdkVersionPolicy();
            //同步IOS 策略总开关
            Map<String, Integer> iosSdkPolicyConfigConfig = syncIosSdkPolicyConfig();
            //同步ios标签策略
            Map<String, Object> iosTarConfigCount = syncIosTagConfig();
            //同步ios205策略
            Map<String, String> ios205Policy =  syncIos205Policy();

            end = System.currentTimeMillis();
            StringBuilder msg = new StringBuilder();
            msg.append("sdk策略同步完成。")
                    .append("\n===================== Android ===============================")
                    .append("\n版本策略关系: ").append(androidSdkVersionPolicy.size() + "条")
                    .append("\n策略总开关: ").append(androidSdkPolicyConfigConfig.size() + "条")
                    .append("\n分辨率: ").append(androidScreenPolicyCount.size() + "条")
                    .append("\n电池: ").append(androidBattaryPolicyCount.size() + "条")
                    .append("\n应用列表: ").append(androidAppsPolicyCount.size() + "条")
                    .append("\n摄像头: ").append(androidCameraPolicyCount.size() + "条")
                    .append("\n环境变量: ").append(androidEnvPolicyCount.size() + "条")
                    .append("\n内存与磁盘: ").append(androidMemPolicyCount.size() + "条")
                    .append("\n异常app包名: ").append(androidSyncBadAppsCount.size()+"条")
                    .append("\n异常辅助功能app包名: ").append(androidSyncBadAccCount.size()+"条")
                    .append("\n异常wifi: ").append(androidSyncBadWifiCount.size()+"条")
                    .append("\n安卓标签: ").append(androidTarConfigCount.size()+"条")
                    .append("\n\n===================== IOS ===============================")
                    .append("\n版本策略关系: ").append(iosSdkVersionPolicy.size()+"条")
                    .append("\n策略总开关: ").append(iosSdkPolicyConfigConfig.size()+"条")
                    .append("\nios标签: ").append(iosTarConfigCount.size()+"条")
                    .append("\n205策略: ").append(ios205Policy.size()+"条")
                    .append("\n用时: ").append((end - start) + "毫秒");
            log.info(msg.toString());

            //如果同步时间超过20分钟 发送钉钉群
            if((end-start)>60000*20){
                dingDingSendMsgUtil.sendMsg(msg.toString());
            }

            //8点推送SDK版本与策略详细信息
            if("08:00".equals(DateUtil.format(new Date(), "HH:mm"))){
                if(env.equals("pro")){
                    msg.append("===================== Android ===============================")
                       .append("\nSDK版本策略关系:\n");
                    for (Map.Entry<String, List<String>> stringListEntry : androidSdkVersionPolicy.entrySet()) {
                        msg.append(stringListEntry.getKey()+":\t");
                        for (String s : stringListEntry.getValue()) {
                            msg.append(s).append("\t");
                        }
                        msg.append("\n");
                    }

                    msg.append("===================== IOS ===============================")
                            .append("\nSDK版本策略关系:\n");
                    for (Map.Entry<String, List<String>> stringListEntry : iosSdkVersionPolicy.entrySet()) {
                        msg.append(stringListEntry.getKey()+":\t");
                        for (String s : stringListEntry.getValue()) {
                            msg.append(s).append("\t");
                        }
                        msg.append("\n");
                    }
                    dingDingSendMsgUtil.sendMsg(msg.toString());
                }
            }
        } catch (Exception exception) {
            //同步失败推送钉钉
            end = System.currentTimeMillis();
            StringBuilder exceptionMsg = new StringBuilder();
            for (StackTraceElement stackTraceElement : exception.getStackTrace()) {
                exceptionMsg.append(stackTraceElement.toString()).append("\n");//拼接堆栈信息
            }

            StringBuilder msg = new StringBuilder();
            msg.append("SDK配置同步失败!!").append("\n")
                    .append("异常信息: ").append(exception.toString()).append("\n")
                    .append("用时: ").append((end - start)).append("毫秒\n")
                    .append("堆栈信息: \n").append(exceptionMsg.toString());
            dingDingSendMsgUtil.sendMsg(msg.toString());
            log.error("同步sdk策略失败!", exception);
        }

    }



    //=========================== IOS =================================

    //同步IOS 策略总开关
    private Map<String, Integer> syncIosSdkPolicyConfig() {
        //获取PolicyConfig
        List<Map<String, Object>> allSdkPolicyConfig = sdkPolicyMapper.findIosSdkPolicyConfigByOn();

        Map<String, Integer> map = new HashMap<>();
        for (Map<String, Object> stringObjectMap : allSdkPolicyConfig) {
            String policy = (String) stringObjectMap.get("policy");
            Integer tag = (Integer) stringObjectMap.get("quanlity");
            policy = policy.trim();
            map.put(policy, tag);
        }

        ddbUtils.putMap(DDBUtils.SDK_POLICY_IOS, SDK_POLICY_PRImMARY_KEY, ALL_STARTEGY, ALL_STARTEGY, map);
        return map;
    }


    //同步IOS 版本与策略对应关系
    private Map<String, List<String>> syncIosSdkVersionPolicy() {

        Map<String, Set<String>> map = new HashMap<>();

        //获取sdk版本与策略关联表
        List<Map<String, Object>> sdkPolicy = sdkPolicyMapper.findIosSdkVersionLinkConfig();

        //封装Map
        for (Map<String, Object> stringObjectMap : sdkPolicy) {
            if(stringObjectMap == null ){
                continue;
            }
            String policyName = (String) stringObjectMap.get("policy_name");
            String sdkVersion = (String) stringObjectMap.get("sdk_version");
            policyName = policyName.trim();
            sdkVersion = sdkVersion.trim();

            if (map.containsKey(sdkVersion)) {
                Set<String> set = map.get(sdkVersion);
                set.add(policyName);
            } else {
                Set<String> policys = new HashSet<>();
                policys.add(policyName);
                map.put(sdkVersion, policys);
            }
        }

        //实时那边需要LIST
        Map<String,List<String>>  ddbMap = new HashMap<>();
        for (Map.Entry<String, Set<String>> stringSetEntry : map.entrySet()) {
            List<String> temp = new ArrayList<>(stringSetEntry.getValue());
            ddbMap.put(stringSetEntry.getKey(),temp);
        }

        //存入ddb
        ddbUtils.putMap(DDBUtils.SDK_POLICY_IOS, SDK_POLICY_PRImMARY_KEY, SDK_VERSION_STARTEGY, SDK_VERSION_STARTEGY, ddbMap);
        return ddbMap;

    }

    //同步IOS标签
    private Map<String, Object> syncIosTagConfig() {
        List<Map<String, Object>>  tagConfigAndroid = sdkPolicyMapper.findIosTagConfigByOn();
        Map<String, Object> ddbMap = new HashMap<>();
        for (Map<String, Object> map : tagConfigAndroid) {
            ddbMap.put((String)map.get("in_tag"),map.get("out_tag"));
        }

        ddbUtils.putMap(DDBUtils.LABEL_MAPPING,"id","label_mapping_ios","value",ddbMap);
        return ddbMap;
    }


    //同步ios205策略
    private Map<String, String> syncIos205Policy() {
        List<Map<String, Object>> ios205Policy = sdkPolicyMapper.findIos205PolicyByOn();

        Map<String, String> ddbMap = new HashMap<>();
        for (Map<String, Object> map : ios205Policy) {
            String model = map.get("model").toString().trim();//设备机型
            String buildVer = map.get("build_ver").toString().trim();//系统构建版本
            String libVers = map.get("lib_vers").toString().trim();//系统库版本
            String key = model+":"+buildVer;
            ddbMap.put(key,libVers);
        }
        ddbUtils.putMap(DDBUtils.SDK_POLICY_IOS,SDK_POLICY_PRImMARY_KEY,IOS_205_CONFIG,IOS_205_CONFIG,ddbMap);
        return ddbMap;
    }



    //=========================== Android =================================

    //同步安卓异常wifi策略
    private List<String> syncAndroidBadWifiPolicy() {
        List<Map<String, Object>>  badWifiPolicyByOn = sdkPolicyMapper.findAndroidBadWifiByOn();
        Set<String> dbSet = new LinkedHashSet<>();
        for (Map<String, Object> map : badWifiPolicyByOn) {
            String wifimac = (String)map.get("wifimac");
            wifimac = wifimac.trim();
            dbSet.add(wifimac);
        }
        List<String> list = new LinkedList<>(dbSet);
        ddbUtils.putList(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, BAD_WIFI_CONFIG, BAD_WIFI_CONFIG, list);
        return list;
    }

    //同步安卓异常辅助功能app包名策略
    private List<String> syncAndroidBadAccPolicy() {
        List<Map<String, Object>> badAppsPolicyByOn = sdkPolicyMapper.findAndroidBadAccPolicyByOn();
        Set<String> dbSet = new LinkedHashSet<>();
        for (Map<String, Object> map : badAppsPolicyByOn) {
            String bundleid = (String)map.get("bundleid");
            bundleid = bundleid.trim();
            dbSet.add(bundleid);
        }
        List<String> list = new LinkedList<>(dbSet);
        ddbUtils.putList(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, BAD_ACC_CONFIG, BAD_ACC_CONFIG, list);
        return list;
    }

    //同步安卓异常app包名策略
    private List<String> syncAndroidBadAppsPolicy() {

        List<Map<String, Object>> badAppsPolicyByOn = sdkPolicyMapper.findAndroidBadAppsPolicyByOn();
        Set<String> dbSet = new LinkedHashSet<>();
        for (Map<String, Object> map : badAppsPolicyByOn) {
            String bundleid = (String)map.get("bundleid");
            bundleid = bundleid.trim();
            dbSet.add(bundleid);
        }
        List<String> list = new LinkedList<>(dbSet);
        ddbUtils.putList(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, BAD_APP_CONFIG, BAD_APP_CONFIG, list);
        return list;
    }


    //同步安卓标签
    private Map<String, Object> syncAndroidTagConfig() {
        List<Map<String, Object>>  tagConfigAndroid = sdkPolicyMapper.findAndroidTagConfigByOn();
        Map<String, Object> ddbMap = new HashMap<>();
        for (Map<String, Object> map : tagConfigAndroid) {
            ddbMap.put((String)map.get("in_tag"),map.get("out_tag"));
        }

         ddbUtils.putMap(DDBUtils.LABEL_MAPPING,"id","label_mapping_android","value",ddbMap);
         return ddbMap;
    }

    //同步安卓内存加磁盘策略  注意: 一个品牌和型号 只能对应一条数据
    private Map<String, String> syncAndroidMemPolicy() {
        List<Map<String, Object>> envPolicyByOn = sdkPolicyMapper.findAndroidMemPolicyByOn();

        Map<String, String> ddbMap = new HashMap<>();
        for (Map<String, Object> map : envPolicyByOn) {
            String key = generateKey(map);
            String mem = (String) map.get("mem");//内存与磁盘
            ddbMap.put(key, mem);
        }
        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, MEM_CONFIG, MEM_CONFIG, ddbMap);
        return ddbMap;
    }

    //同步安卓环境变量策略  注意: 一个品牌 只能对应一条数据
    private Map<String, String> syncAndroidEnvPolicy() {
        List<Map<String, Object>> envPolicyByOn = sdkPolicyMapper.findAndroidEnvPolicyByOn();
        Map<String, String> ddbMap = new HashMap<>();

        for (Map<String, Object> map : envPolicyByOn) {
            String key = generateKey(map);
            Map<String, Object> value = new HashMap<>();
            value.put("env", map.get("env"));//环境变量
            value.put("min", map.get("min"));//最小个数
            ddbMap.put(key, JSONUtil.toJsonStr(value));
        }
        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, ENV_CONFIG, ENV_CONFIG, ddbMap);
        return ddbMap;
    }

    //同步安卓摄像头策略  注意: 该表中一个品牌与型号 可以有多条数据
    private Map<String,List<String>> syncAndroidCameraPolicy() {
        List<Map<String, Object>> CameraPolicyByOn = sdkPolicyMapper.findAndroidCameraPolicyByOn();

        Map<String, Set<String>> setMap = new HashMap<>();
        for (Map<String, Object> map : CameraPolicyByOn) {
            String key = generateKey(map);
            String value = (String) map.get("camera");//摄像头参数

            if (setMap.containsKey(key)) {
                Set<String> set = setMap.get(key);
                set.add(value);
            } else {
                Set<String> set = new HashSet<>();
                set.add(value);
                setMap.put(key, set);
            }
        }

        //实时那边需要LIST
        Map<String,List<String>>  ddbMap = new HashMap<>();
        for (Map.Entry<String, Set<String>> stringSetEntry : setMap.entrySet()) {
            List<String> temp = new ArrayList<>(stringSetEntry.getValue());
            ddbMap.put(stringSetEntry.getKey(),temp);
        }

        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, CAMERA_CONFIG, CAMERA_CONFIG, ddbMap);
        return ddbMap;
    }


    //同步安卓应用列表策略  注意: 一个品牌 只能对应一条数据
    private Map<String, String> syncAndroidAppsPolicy() {
        List<Map<String, Object>> appsPolicyByOn = sdkPolicyMapper.findAndroidAppsPolicyByOn();

        Map<String, String> ddbMap = new HashMap<>();
        for (Map<String, Object> map : appsPolicyByOn) {
            String key = generateKey(map);
            Map<String, Object> value = new HashMap<>();
            value.put("apps", map.get("apps"));//应用包名集合
            value.put("min", map.get("min"));//最小应用数
            ddbMap.put(key, JSONUtil.toJsonStr(value));
        }
        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, APPS_CONFIG, APPS_CONFIG, ddbMap);
        return ddbMap;
    }

    //同步安卓电池策略  注意: 一个品牌和型号 只能对应一条数据
    private Map<String, String> syncAndroidBattaryPolicy() {

        List<Map<String, Object>> battaryPolicyByOn = sdkPolicyMapper.findAndroidBattaryPolicyByOn();

        Map<String, String> ddbMap = new HashMap<>();
        for (Map<String, Object> map : battaryPolicyByOn) {
            String key = generateKey(map);
            Map<String, Object> value = new HashMap<>();
            value.put("min", map.get("min"));//最小容量
            value.put("max", map.get("max"));//最小容量
            ddbMap.put(key, JSONUtil.toJsonStr(value));
        }
        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, BATTARY_CONFIG, BATTARY_CONFIG, ddbMap);
        return ddbMap;
    }

    //同步安卓分辨率策略  注意: 该表中一个品牌与型号 可以有多条数据
    private Map<String,List<String>> syncAndroidScreenPolicy() {
        List<Map<String, Object>> screenPolicyByOn = sdkPolicyMapper.findAndroidScreenPolicyByOn();

        Map<String, Set<String>> setMap = new HashMap<>();
        for (Map<String, Object> map : screenPolicyByOn) {
            String key = generateKey(map);
            Map<String, Object> value = new HashMap<>();
            value.put("dpi", map.get("dpi"));//屏幕密度
            value.put("w", map.get("w"));//宽
            value.put("h", map.get("h"));//高

            if (setMap.containsKey(key)) {
                Set<String> set = setMap.get(key);
                set.add(JSONUtil.toJsonStr(value));
            } else {
                Set<String> set = new HashSet<>();
                set.add(JSONUtil.toJsonStr(value));
                setMap.put(key, set);
            }
        }

        //实时那边需要LIST
        Map<String,List<String>>  ddbMap = new HashMap<>();
        for (Map.Entry<String, Set<String>> stringSetEntry : setMap.entrySet()) {
            List<String> temp = new ArrayList<>(stringSetEntry.getValue());
            ddbMap.put(stringSetEntry.getKey(),temp);
        }

        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, SCREEN_CONFIG, SCREEN_CONFIG, ddbMap);
        return ddbMap;
    }


    /**
     * 同步安卓策略总开关
     */
    private Map<String, Integer> syncAndroidSdkPolicyConfig() {

        //获取PolicyConfig
        List<Map<String, Object>> allSdkPolicyConfig = sdkPolicyMapper.findAndroidSdkPolicyConfigByOn();

        Map<String, Integer> map = new HashMap<>();
        for (Map<String, Object> stringObjectMap : allSdkPolicyConfig) {
            String policy = (String) stringObjectMap.get("policy");
            Integer tag = (Integer) stringObjectMap.get("quanlity");
            policy = policy.trim();
            map.put(policy, tag);
        }

        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, ALL_STARTEGY, ALL_STARTEGY, map);
        return map;
    }


    /**
     * 同步安卓sdk版本与策略对应关系
     */
    private Map<String,List<String>> syncAndroidSdkVersionPolicy() {

        Map<String, Set<String>> map = new HashMap<>();

        //获取sdk版本与策略关联表
        List<Map<String, Object>> sdkPolicy = sdkPolicyMapper.findAndroidSdkVersionLinkConfig();

        //封装Map
        for (Map<String, Object> stringObjectMap : sdkPolicy) {
            if(stringObjectMap == null ){
                continue;
            }
            String policyName = (String) stringObjectMap.get("policy_name");
            String sdkVersion = (String) stringObjectMap.get("sdk_version");
            policyName = policyName.trim();
            sdkVersion = sdkVersion.trim();

            if (map.containsKey(sdkVersion)) {
                Set<String> set = map.get(sdkVersion);
                set.add(policyName);
            } else {
                Set<String> policys = new HashSet<>();
                policys.add(policyName);
                map.put(sdkVersion, policys);
            }
        }

        //实时那边需要LIST
        Map<String,List<String>>  ddbMap = new HashMap<>();
        for (Map.Entry<String, Set<String>> stringSetEntry : map.entrySet()) {
            List<String> temp = new ArrayList<>(stringSetEntry.getValue());
            ddbMap.put(stringSetEntry.getKey(),temp);
        }

        //存入ddb
        ddbUtils.putMap(DDBUtils.SDK_POLICY_ANDROID, SDK_POLICY_PRImMARY_KEY, SDK_VERSION_STARTEGY, SDK_VERSION_STARTEGY, ddbMap);
        return ddbMap;

    }


    /**
     * 生成ddb表item中的map属性的键
     *
     * @param source mysql中的一条数据
     * @return
     */
    private String generateKey(Map<String, Object> source) {
        String b1 = (String) source.get("b1");//品牌
        String by = (String) source.get("by");//型号

        //去除空格
        b1 = StringUtils.isEmpty(b1)?b1:b1.trim();
        by = StringUtils.isEmpty(by)?by:by.trim();


        String result = "未知的key";
        if (!StringUtils.isEmpty(b1)
                && !StringUtils.isEmpty(by)) {//品牌与型号都不为空

            //统一规范  b1和by转为大写
            b1 = b1.toUpperCase();
            by = by.toUpperCase();
            result = b1 + ":" + by;
        } else if (!StringUtils.isEmpty(b1)
                && StringUtils.isEmpty(by)) {//品牌不为空  型号为空
            //统一规范  b1转为大写
            b1 = b1.toUpperCase();
            result = b1;
        }
        return result;
    }


    public static void main(String[] args) {
        String format = DateUtil.format(new Date(), "HH:mm");
        System.out.println(format);
    }
}
