package com.jeequan.jeepay.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.*;
import com.jeequan.jeepay.core.service.ISysConfigService;
import com.jeequan.jeepay.db.entity.SysConfig;
import com.jeequan.jeepay.service.mapper.SysConfigMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 系统配置表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2020-07-29
 */
@Service
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {

    @Autowired
    private CacheTkService cacheTkService;

    /** 是否启用缓存
     * true: 表示将使用内存缓存， 将部分系统配置项 或 商户应用/服务商信息进行缓存并读取
     * false: 直接查询DB
     * **/
    public static boolean IS_USE_CACHE = false;

    /** 系统是否支持服务商模式。 若不支持则不显示部分服务商功能  **/
    public static boolean IS_HAS_AGENT_ENT = false;

    /** 系统是否支持会员模式。 若不支持则不显示部分会员功能  **/
    public static boolean IS_HAS_MEMBER_ENT = false;

    /** http通信是否优先使用加密数据传输 */
    public static boolean HTTP_MSG_IS_ENCRYPT = false;

    /** 密码过期是否需强制更改 */
    public static boolean PWD_EXPIRED_MUST_RESET = false;

    /** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同，否则加解密不一致导致业务异常！] **/
    public static String DB_ENCRYPT_SECRET = null;
    public static SM4 DB_ENCRYPT_SM4 = null;

    /** web传输加解密 秘钥 (必须16位) [每个系统配置必须相同，否则加解密不一致导致业务异常！] **/
    public static String HTTP_MESSAGE_ENCRYPT_SECRET = null;
    public static SM4 HTTP_MESSAGE_ENCRYPT_SM4 = null;

    /** 平台通信秘钥 当通过平台操作接口（比如：下单、退款）时将传入该值，用于区分是平台调用还是商户自调用。 **/
    public static String PLATFORM_API_SECRET = "qUYbn2%xaJz#wST+";

    /** 检查是否包含服务商的配置项， 当没有此配置表示不支持服务商 **/
    public static final String AGENT_ENT_CONFIG = "agentSiteUrl";

    /** 检查是否包含会员网关的配置项， 当没有此配置表示不支持会员 **/
    public static final String MEMBER_ENT_CONFIG = "memberSiteUrl";

    /** 数据库application配置参数 **/
    private static MutablePair<String, DBApplicationConfig> APPLICATION_CONFIG = new MutablePair<>("applicationConfig", null);

    /** 微信提醒配置参数 **/
    public static MutablePair<String, DBWxMpConfig> WXMP_CONFIG = new MutablePair<>("wxMpConfig", null);

    /** OCR配置参数 **/
    public static MutablePair<String, DBOCRConfig> OCR_CONFIG = new MutablePair<>("ocrConfig", null);

    /** OSS配置参数 **/
    public static MutablePair<String, DBOSSConfig> OSS_CONFIG = new MutablePair<>("ossConfig", null);

    /** OEM 配置参数 **/
    private static MutablePair<String, DBOEMConfig> OEM_CONFIG = new MutablePair<>("oemConfig", null);

    /** 消息推送 配置参数 **/
    public static MutablePair<String, DBAppPushConfig> APP_PUSH_CONFIG = new MutablePair<>("appPushConfig", null);

    /** 百度语音 配置参数 **/
    public static MutablePair<String, DBBaiduBceConfig> BAIDU_BCE_CONFIG = new MutablePair<>("baiduBceConfig", null);

    /** 隐私协议与服务政策 配置参数 **/
    private static MutablePair<String, DBTreatyConfig> TREATY_CONFIG = new MutablePair<>("treatyConfig", null);

    /** 高德地图 配置参数 **/
    public static MutablePair<String, DBApiMapConfig> API_MAP_CONFIG = new MutablePair<>("apiMapConfig", null);

    /** 系统安全 配置参数 **/
    public static MutablePair<String, DBsecurityConfig> SECURITY_CONFIG = new MutablePair<>("securityConfig", null);

    /** 默认配置 配置参数 **/
    public static MutablePair<String, DBDefaultConfig> DEFAULT_CONFIG = new MutablePair<>("defaultConfig", null);

    /** 邮件相关配置 **/
    public static MutablePair<String, DBEmailConfig> EMAIL_CONFIG = new MutablePair<>("emailConfig", null);

    /** 邮件相关配置 **/
    public static MutablePair<String, DBMarketingConfig> MARKETING_CONFIG = new MutablePair<>("marketingConfig", null);

    /** 打款相关配置 **/
    public static MutablePair<String, DBPaymentConfig> PAYMENT_CONFIG = new MutablePair<>("paymentConfig", null);

    public synchronized void initDBConfig(String groupKey) {

        // 不管是否开启缓存， 此配置都需要更新。
        if(SECURITY_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            SECURITY_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBsecurityConfig.class);
            SysConfigService.HTTP_MSG_IS_ENCRYPT = SECURITY_CONFIG.right.httpMsgIsEncrypt(); //重置静态属性
            SysConfigService.PWD_EXPIRED_MUST_RESET = SECURITY_CONFIG.right.passwordExpiredIsMustModify(); //重置静态属性
            SysConfigService.PLATFORM_API_SECRET = SECURITY_CONFIG.right.getPlatformApiSecret(); //重置静态属性
        }

        // 若当前系统不缓存，则直接返回
        if(!IS_USE_CACHE){
            return;
        }

        if(APPLICATION_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            APPLICATION_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBApplicationConfig.class);
        }else if(WXMP_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            WXMP_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBWxMpConfig.class);
        }else if(OCR_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            OCR_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBOCRConfig.class);
        }else if(OSS_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            OSS_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBOSSConfig.class);
        }else if(TREATY_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            TREATY_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBTreatyConfig.class);
        }else if(OEM_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            SysConfig sysConfig = this.getById(OEM_CONFIG.getLeft());
            OEM_CONFIG.right = sysConfig == null ? new DBOEMConfig() : JSON.parseObject(sysConfig.getConfigVal(), DBOEMConfig.class);
        }else if(APP_PUSH_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            APP_PUSH_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBAppPushConfig.class);
        }else if(BAIDU_BCE_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            BAIDU_BCE_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBBaiduBceConfig.class);
        }else if(API_MAP_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            API_MAP_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBApiMapConfig.class);
        }else if(DEFAULT_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            DEFAULT_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBDefaultConfig.class);
        }else if(EMAIL_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            EMAIL_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBEmailConfig.class);
        }else if(MARKETING_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            MARKETING_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBMarketingConfig.class);
        }else if(PAYMENT_CONFIG.getLeft().equalsIgnoreCase(groupKey)){
            PAYMENT_CONFIG.right = this.selectByGroupKey(groupKey).toJavaObject(DBPaymentConfig.class);
        }
    }

    /** 获取实际的数据 **/
    @Override
    public DBApplicationConfig getDBApplicationConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(APPLICATION_CONFIG.getLeft()).toJavaObject(DBApplicationConfig.class);
        }

        // 缓存数据
        if(APPLICATION_CONFIG.getRight() == null ){
            initDBConfig(APPLICATION_CONFIG.getLeft());
        }
        return APPLICATION_CONFIG.right;
    }

    /** 获取微信提醒配置参数 **/
    @Override
    public DBWxMpConfig getDBWxMpConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(WXMP_CONFIG.getLeft()).toJavaObject(DBWxMpConfig.class);
        }

        if(WXMP_CONFIG.getRight() == null ){
            initDBConfig(WXMP_CONFIG.getLeft());
        }
        return WXMP_CONFIG.right;
    }

    /** 获取OCR配置参数 **/
    @Override
    public DBOCRConfig getOcrConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(OCR_CONFIG.getLeft()).toJavaObject(DBOCRConfig.class);
        }

        if(OCR_CONFIG.getRight() == null){
            initDBConfig(OCR_CONFIG.getLeft());
        }
        return OCR_CONFIG.right;
    }

    /** 获取OSS配置参数 **/
    @Override
    public DBOSSConfig getOssConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(OSS_CONFIG.getLeft()).toJavaObject(DBOSSConfig.class);
        }

        if(OSS_CONFIG.getRight() == null){
            initDBConfig(OSS_CONFIG.getLeft());
        }
        return OSS_CONFIG.right;
    }

    /** 获取OSS配置参数 **/
    @Override
    public DBEmailConfig getEmailConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(EMAIL_CONFIG.getLeft()).toJavaObject(DBEmailConfig.class);
        }
        if(EMAIL_CONFIG.getRight() == null){
            initDBConfig(EMAIL_CONFIG.getLeft());
        }
        return EMAIL_CONFIG.right;
    }

    /** 获取OSS配置参数 **/
    @Override
    public DBTreatyConfig getTreatyConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(TREATY_CONFIG.getLeft()).toJavaObject(DBTreatyConfig.class);
        }

        if(OSS_CONFIG.getRight() == null){
            initDBConfig(TREATY_CONFIG.getLeft());
        }
        return TREATY_CONFIG.right;
    }


    /** 获取OSS配置参数 **/
    @Override
    public DBOEMConfig getOemConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            SysConfig sysConfig = this.getById(OEM_CONFIG.getLeft());
            return sysConfig == null ? new DBOEMConfig() : JSON.parseObject(sysConfig.getConfigVal(), DBOEMConfig.class);
        }

        if(OEM_CONFIG.getRight() == null){
            initDBConfig(OEM_CONFIG.getLeft());
        }
        return OEM_CONFIG.right;
    }

    /** 获取APP  PUSH配置参数 **/
    @Override
    public DBAppPushConfig getDBAppPushConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(APP_PUSH_CONFIG.getLeft()).toJavaObject(DBAppPushConfig.class);
        }

        if(APP_PUSH_CONFIG.getRight() == null ){
            initDBConfig(APP_PUSH_CONFIG.getLeft());
        }
        return APP_PUSH_CONFIG.right;
    }

    /** 获取百度语音配置参数 **/
    @Override
    public DBBaiduBceConfig getDBBaiduBceConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(BAIDU_BCE_CONFIG.getLeft()).toJavaObject(DBBaiduBceConfig.class);
        }

        if(BAIDU_BCE_CONFIG.getRight() == null ){
            initDBConfig(BAIDU_BCE_CONFIG.getLeft());
        }
        return BAIDU_BCE_CONFIG.right;
    }

    /** 获取百度语音配置参数 **/
    @Override
    public DBApiMapConfig getDBApiMapConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(API_MAP_CONFIG.getLeft()).toJavaObject(DBApiMapConfig.class);
        }

        if(API_MAP_CONFIG.getRight() == null ){
            initDBConfig(API_MAP_CONFIG.getLeft());
        }
        return API_MAP_CONFIG.right;
    }

    @Override
    public DBsecurityConfig getDBSecurityConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(SECURITY_CONFIG.getLeft()).toJavaObject(DBsecurityConfig.class);
        }

        if(SECURITY_CONFIG.getRight() == null ){
            initDBConfig(SECURITY_CONFIG.getLeft());
        }
        return SECURITY_CONFIG.right;
    }

    @Override
    public DBDefaultConfig getDBDefaultConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(DEFAULT_CONFIG.getLeft()).toJavaObject(DBDefaultConfig.class);
        }

        if(DEFAULT_CONFIG.getRight() == null ){
            initDBConfig(DEFAULT_CONFIG.getLeft());
        }
        return DEFAULT_CONFIG.right;
    }

    @Override
    public SM4 getHttpMessageSM4() {
        return HTTP_MESSAGE_ENCRYPT_SM4;
    }

    /** 根据分组查询，并返回JSON对象格式的数据 **/
    public JSONObject selectByGroupKey(String groupKey){

        JSONObject result = new JSONObject();
        list(SysConfig.gw().select(SysConfig::getConfigKey, SysConfig::getConfigVal).eq(SysConfig::getGroupKey, groupKey))
        .stream().forEach(item -> result.put(item.getConfigKey(), item.getConfigVal()));
        return result;
    }


    public int updateByConfigKey(Map<String, String> updateMap) {
        int count = 0;
        Set<String> set = updateMap.keySet();
        for(String k : set) {
            SysConfig sysConfig = new SysConfig();
            sysConfig.setConfigKey(k);
            sysConfig.setConfigVal(updateMap.get(k));
            boolean update = saveOrUpdate(sysConfig);
            if (update) {
                count ++;
            }
        }
        return count;
    }

    /** 查询密码原文 **/
    public String queryDefaultPasswordRaw(){
        return Base64.decodeStr(getById("defaultPassword").getConfigVal());
    }


    /** 查询商户自主进件是否需要预审核 系统默认配置 */
    public boolean queryMchApplymentPreAudit(){
        return "1".equals(this.getById("mchApplymentPreAudit").getConfigVal());
    }

    /** 查询商户自主进件是否在允许的时间范围内 系统默认配置 */
    public boolean queryMchApplymentTimeLimit(){
        return !applyTimeLimit(this.getById("mchApplyTimeLimit").getConfigVal());
    }

    /** 查询商户自主进件允许的时间范围 系统默认配置 */
    public String queryMchApplymentTime(){
        return applyTimeLimitStr(this.getById("mchApplyTimeLimit").getConfigVal());
    }

    /** 查询配置的值信息 */
    public String selectConfigVal(String configKey){
        SysConfig sysConfig = this.getOne(SysConfig.gw()
                .select(SysConfig::getConfigVal)
                .eq(SysConfig::getConfigKey, configKey));

        return (sysConfig == null ? null :sysConfig.getConfigVal());
    }

    public boolean applyTimeLimit(String applyTimeLimit){
        if (StringUtils.isEmpty(applyTimeLimit)){
            // 为null时不限制时间
            return true;
        }
        boolean minLimit = true, maxLimit = true;
        JSONArray timeArray = JSONArray.parseArray(applyTimeLimit);
        int applyCreatDate = Integer.parseInt(DateUtil.format(new Date(), "HHmmss"));
        if (StringUtils.isNotEmpty(timeArray.getString(0))){
            int minLimitDate = Integer.parseInt(timeArray.getString(0).replaceAll(":", ""));
            minLimit =  applyCreatDate >= minLimitDate;
        }
        if (StringUtils.isNotEmpty(timeArray.getString(1))){
            int maxLimitDate = Integer.parseInt(timeArray.getString(1).replaceAll(":", ""));
            maxLimit =  applyCreatDate <= maxLimitDate;
        }
        return minLimit && maxLimit;
    }

    public String applyTimeLimitStr(String applyTimeLimit){
        if (StringUtils.isEmpty(applyTimeLimit)){
            // 为null时不限制时间
            return "任意时间";
        }
        String minLimit = "00:00:00", maxLimit = "23:59:59";
        JSONArray timeArray = JSONArray.parseArray(applyTimeLimit);
        if (StringUtils.isNotEmpty(timeArray.getString(0))){
            minLimit =  timeArray.getString(0);
        }
        if (StringUtils.isNotEmpty(timeArray.getString(1))){
            maxLimit = timeArray.getString(1);
        }
        return minLimit + "~" + maxLimit;
    }

    /**
     * 查询短信厂商和对应的配置
     **/
    public MutablePair<String, String> getSmsConfigInfo() {
        // 查询使用的哪个厂商
        SysConfig smsProvideConfig = this.getById("smsProvideKey");
        if (smsProvideConfig == null || smsProvideConfig.getConfigVal() == null) {
            throw new BizException("短信厂商信息未配置");
        }
        // 根据厂商类型查询对应的配置Val
        String configKey = smsProvideConfig.getConfigVal() + "SmsConfigValue";
        SysConfig sysConfig = this.getById(configKey);
        if (sysConfig == null) {
            throw new BizException("短信配置获取失败");
        }
        return MutablePair.of(smsProvideConfig.getConfigVal(), sysConfig.getConfigVal());
    }

    @Override
    public DBMarketingConfig getDBMarketingConfig() {
        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(MARKETING_CONFIG.getLeft()).toJavaObject(DBMarketingConfig.class);
        }
        if(MARKETING_CONFIG.getRight() == null ){
            initDBConfig(MARKETING_CONFIG.getLeft());
        }
        return MARKETING_CONFIG.right;
    }

    /**
     * 获取红包配置是否开启
     * @return
     */
    @Override
    public Boolean getDbMarketPlatRedPacket() {
        DBMarketingConfig dbMarketingConfig = getDBMarketingConfig();
        return CS.YES == Byte.valueOf(dbMarketingConfig.getPlatRedPacket()) ? true : false;
    }


    @Override
    public String genQrToken(Byte type, String id,Long amt) {
        return cacheTkService.initSave(type, id,amt);
    }


    /** 获取打款参数 **/
    @Override
    public DBPaymentConfig getDbPaymentConfig() {

        // 查询DB
        if(!IS_USE_CACHE){
            return this.selectByGroupKey(PAYMENT_CONFIG.getLeft()).getJSONObject(PAYMENT_CONFIG.getLeft()).toJavaObject(DBPaymentConfig.class);
        }

        if(PAYMENT_CONFIG.getRight() == null ){
            initDBConfig(PAYMENT_CONFIG.getLeft());
        }
        return PAYMENT_CONFIG.right;
    }
}
