
package com.tmerclub.cloud.platform.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.feign.AuthSocialFeignClient;
import com.tmerclub.cloud.api.distribution.feign.DistributionFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.order.feign.OrderFeignClient;
import com.tmerclub.cloud.api.payment.constant.PaySysType;
import com.tmerclub.cloud.api.platform.vo.DistributionConfigApiVO;
import com.tmerclub.cloud.api.supplier.feign.SupplierDetailFeignClient;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.common.bean.*;
import com.tmerclub.cloud.common.cache.constant.ConfigCacheNames;
import com.tmerclub.cloud.common.cache.constant.OauthCacheNames;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.platform.mapper.SysConfigMapper;
import com.tmerclub.cloud.platform.model.SysConfig;
import com.tmerclub.cloud.platform.service.SysConfigService;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 系统配置信息表
 *
 * @author lhd
 * @date 2020-12-23 16:27:57
 */
@Service
public class SysConfigServiceImpl implements SysConfigService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SysConfigServiceImpl.class);

    @Resource
    private SysConfigMapper sysConfigMapper;
    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;
    @DubboReference
    private SupplierDetailFeignClient supplierDetailFeignClient;
    @DubboReference
    private OrderFeignClient orderFeignClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @DubboReference
    private UserFeignClient userFeignClient;
    @DubboReference
    private AuthSocialFeignClient authSocialFeignClient;
    @DubboReference
    private DistributionFeignClient distributionFeignClient;
    @Autowired
    private RocketMQTemplate openAllinPayRocketMQTemplate;

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG_OBJECT, key = "#key"),
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG, key = "#key")
    })
    public void updateValueByKey(String key, String value) {
//        sysConfigMapper.updateValueByKey(key, value);
    }

    @Override
    public void deleteBatch(Long[] ids) {
//        sysConfigMapper.deleteBatch(ids);
    }

    @Override
    @Cacheable(cacheNames = ConfigCacheNames.SYS_CONFIG_VALUE, key = "#key")
    public String getValue(String key) {
        SysConfig config = sysConfigMapper.queryByKey(key);
        return config == null ? null : config.getParamValue();
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG_OBJECT, key = "#key"),
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG_VALUE, key = "#key"),
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG, key = "#key")
    })
    public void removeSysConfig(String key) {
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG_OBJECT, key = "#sysConfig.paramKey"),
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG_VALUE, key = "#sysConfig.paramKey"),
            @CacheEvict(cacheNames = ConfigCacheNames.SYS_CONFIG, key = "#sysConfig.paramKey")
    })
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateSysConfig(SysConfig sysConfig) {
        if (sysConfigMapper.countByKey(sysConfig.getParamKey()) > 0) {
            sysConfigMapper.update(sysConfig);
        } else {
            sysConfigMapper.save(sysConfig);
        }
        if (Objects.equals(sysConfig.getParamKey(), Constant.PAY_SETTLEMENT_CONFIG)) {
            handleAllinpay(sysConfig);
        }
    }

    private void handleAllinpay(SysConfig sysConfig) {
        PaySettlementConfig paySettlementConfig = Json.parseObject(sysConfig.getParamValue(), PaySettlementConfig.class);
        String value = getValue(Constant.PAY_SETTLEMENT_CONFIG);
        PaySettlementConfig dbValue = Json.parseObject(value, PaySettlementConfig.class);
        if (Objects.equals(dbValue.getPaySettlementType(), 1) && Objects.equals(paySettlementConfig.getPaySettlementType(), 0)) {
            throw new LuckException("通联支付开启后无法关闭");
        }
        // 修改支付系统类型
        if (Objects.equals(paySettlementConfig.getPaySettlementType(), 1)) {
            // 取消分销配置中分销员申请所需信息
            SysConfigService sysConfigService = (SysConfigService) AopContext.currentProxy();
            SysConfig distributionConfig = sysConfigMapper.queryByKey(Constant.DISTRIBUTION_CONFIG);
            DistributionConfigApiVO configApiVO = Json.parseObject(distributionConfig.getParamValue(), DistributionConfigApiVO.class);
            configApiVO.setIdentityCardNumber(false);
            configApiVO.setIdentityCardPic(false);
            configApiVO.setRealName(false);
            distributionConfig.setParamValue(Json.toJsonString(configApiVO));
            sysConfigService.saveOrUpdateSysConfig(distributionConfig);
            // 删除缓存
            deleteAllinpayCache();
            // TODO 发送事件，应该把用户相关改下，目前暂时只处理了订单、商家、供应商
            // 将待采购和待付尾款订单进行退款
            // 给商家&供应商还没有通联会员账号的添加会员账号
            SendStatus openAllinpayStatus = openAllinPayRocketMQTemplate.syncSend(RocketMqConstant.OPEN_ALLINPAY_TOPIC,new GenericMessage<>(PaySysType.ALLINPAY.value())).getSendStatus();
            if (!Objects.equals(openAllinpayStatus, SendStatus.SEND_OK)) {
                LOGGER.error("通联开启发送消息失败");
            }
            // 分销初始化
            ServerResponseEntity<Void> distributionResponse = distributionFeignClient.initDistributionBySwitchAllinpay();
            if (!distributionResponse.isSuccess()) {
                LOGGER.error("分销初始化失败{}", distributionResponse.getMsg());
            }
            // 给用户创建通联个人会员
            ServerResponseEntity<Void> userResponse = userFeignClient.createAllinpayMember();
            if (!userResponse.isSuccess()) {
                LOGGER.error("用户端批量创建会员失败{}", userResponse.getMsg());
            }
            // 给第三方注册账号的通联账号绑定支付标识
            ServerResponseEntity<Void> bindPayAcctResponse = authSocialFeignClient.bindAllinpayPayAcct();
            if (!bindPayAcctResponse.isSuccess()) {
                LOGGER.error("给第三方注册账号的通联账号绑定支付标识失败{}", bindPayAcctResponse.getMsg());
            }
        }
    }

    private void deleteAllinpayCache() {
        shopDetailFeignClient.deleteAllinpayCache();
        orderFeignClient.deleteAllinpayCache();
        supplierDetailFeignClient.deleteAllinpayCache();
        // 强制删除所有token，需要用户重新登录来展示通联新页面
        Set<String> tokens = stringRedisTemplate.keys(OauthCacheNames.USER_INFO + "*");
        if (Objects.nonNull(tokens) && CollUtil.isNotEmpty(tokens)) {
            stringRedisTemplate.delete(tokens);
            for (String token : tokens) {
                String[] values = token.split(":");
                // token格式是tmerclub_oauth:token:user_info:6**********************0
                String value = values[values.length - 1];
                StpUtil.logoutByTokenValue(value);
            }
        }
    }

    @Override
    @Cacheable(cacheNames = ConfigCacheNames.SYS_CONFIG, key = "#key")
    public SysConfig getByKey(String key) {
        return sysConfigMapper.queryByKey(key);
    }

    @Override
    public List<String> saveDeliveryConfig(SysConfig sysConfig) {
        // 失效的缓存keys
        List<String> invalidKeys = new ArrayList<>(Constant.INITIAL_CAPACITY);
        SwitchBaseModel switchBaseModel = Json.parseObject(sysConfig.getParamValue(), SwitchBaseModel.class);
        if (BooleanUtil.isTrue(switchBaseModel.getIsOpen())) {
            // 关闭其他物流查询配置
            if (!Objects.equals(sysConfig.getParamKey(), Constant.ALI_QUICK_CONFIG)) {
                // 关闭阿里快递查询
                this.closeSwitch(Constant.ALI_QUICK_CONFIG, AliQuick.class, invalidKeys);
            }
            if (!Objects.equals(sysConfig.getParamKey(), Constant.QUICK100_CONFIG)) {
                // 关闭快递100查询
                this.closeSwitch(Constant.QUICK100_CONFIG, Quick100.class, invalidKeys);
            }
            if (!Objects.equals(sysConfig.getParamKey(), Constant.QUICKBIRD_CONFIG)) {
                // 关闭快递鸟查询
                this.closeSwitch(Constant.QUICKBIRD_CONFIG, QuickBird.class, invalidKeys);
            }
            // 如果有新增的物流查询配置，在这里补上关闭的代码
        }
        // 保存当前物流查询配置
        this.saveOrUpdateSysConfig(sysConfig);
        invalidKeys.add(sysConfig.getParamKey());
        return invalidKeys;
    }

    /**
     * 关闭激活开关
     *
     * @param key         配置项key
     * @param clazz       继承了SwitchBaseModel的类
     * @param invalidKeys 缓存失效的配置集合
     * @param <T>
     */
    public <T> void closeSwitch(String key, Class<T> clazz, List<String> invalidKeys) {
        if (!SwitchBaseModel.class.isAssignableFrom(clazz)) {
            // 不是配置开关属性类的子类不能调用该方法
            return;
        }
        T valueObj = this.getSysConfigObject(key, clazz);
        if (Objects.isNull(valueObj)) {
            // 当前配置在数据库不存在
            return;
        }
        try {
            PropertyDescriptor pd = new PropertyDescriptor("isOpen", clazz);
            Method readMethod = pd.getReadMethod();
            if (BooleanUtil.isFalse((Boolean) readMethod.invoke(valueObj))) {
                // isOpen已经是关闭状态，直接返回
                return;
            }
            Method writeMethod = pd.getWriteMethod();
            // 关闭当前配置
            writeMethod.invoke(valueObj, false);
        } catch (Exception e) {
            return;
        }
        String str = Json.toJsonString(valueObj);
        sysConfigMapper.updateValueByKey(key, str);
        invalidKeys.add(key);
    }

    @Override
    @Cacheable(cacheNames = ConfigCacheNames.SYS_CONFIG_OBJECT, key = "#key")
    @SuppressWarnings("unchecked")
    public <T> T getSysConfigObject(String key, Class<T> clazz) {
        String value = getValue(key);
        if (StrUtil.isBlank(value)) {
            return null;
        }

        if (Objects.equals(String.class, clazz)) {
            return (T) value;
        } else {
            return Json.parseObject(value, clazz);
        }
    }
}
