package com.hys.app.service.base.service.impl;

import com.hys.app.framework.exception.ServiceException;
import com.hys.app.model.base.CachePrefix;
import com.hys.app.model.base.SceneType;
import com.hys.app.model.base.SettingGroup;
import com.hys.app.model.base.message.SmsSendMsg;
import com.hys.app.model.base.vo.ConfigItem;
import com.hys.app.model.base.vo.SmsSendVO;
import com.hys.app.model.errorcode.SystemErrorCode;
import com.hys.app.model.system.dos.SmsTemplate;
import com.hys.app.model.system.enums.EnableStatusEnum;
import com.hys.app.model.system.enums.SmsServiceCodeEnum;
import com.hys.app.service.base.plugin.sms.SmsPlatform;
import com.hys.app.model.base.rabbitmq.AmqpExchange;
import com.hys.app.service.base.service.SettingManager;
import com.hys.app.service.base.service.SmsManager;
import com.hys.app.service.system.SmsTemplateManager;
import com.hys.app.service.system.impl.RandomCreate;
import com.hys.app.model.system.vo.SiteSetting;
import com.hys.app.model.system.vo.SmsPlatformVO;
import com.hys.app.service.system.factory.SmsFactory;
import com.hys.app.framework.ErpConfig;
import com.hys.app.framework.cache.Cache;
import com.hys.app.framework.logs.Debugger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hys.app.framework.util.JsonUtil;
import com.hys.app.framework.util.StringUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.text.StrSubstitutor;
import com.hys.app.framework.rabbitmq.MessageSender;
import com.hys.app.framework.rabbitmq.MqMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 手机短信实现
 *
 * @author zh
 * @version v7.0
 * @since v7.0.0
 * 2018年3月19日 下午4:01:49
 */
@Service
public class SmsManagerImpl implements SmsManager {

    @Autowired
    private SettingManager settingManager;

    @Autowired
    private Cache cache;

    @Autowired
    private ErpConfig erpConfig;

    @Autowired
    private MessageSender messageSender;

    protected static final Logger logger = LoggerFactory.getLogger(SmsManagerImpl.class);

    @Autowired
    private Debugger debugger;

    @Autowired
    private SmsFactory smsFactory;

    @Autowired
    private SmsTemplateManager smsTemplateManager;

    @Override
    public void send(String phoneNumber, SmsServiceCodeEnum serviceCode, Map<String, Object> valuesMap) {
        //查询当前开启的短信平台的模板
        SmsTemplate smsTemplate = smsTemplateManager.getOpenTemplate(serviceCode);
        if(smsTemplate == null){
            logger.debug("未找到短信模板：" + serviceCode);
            return;
        }

        if(!EnableStatusEnum.OPEN.value().equals(smsTemplate.getEnableStatus())){
            logger.debug("短信模板：" + serviceCode + " 未开启");
            return;
        }

        //发送短信参数
        SmsSendVO smsSendVO = new SmsSendVO();
        smsSendVO.setMobile(phoneNumber);
        smsSendVO.setContent(this.replaceContent(smsTemplate.getTemplateContent(), valuesMap));
        smsSendVO.setTemplateCode(smsTemplate.getTemplateCode());
        smsSendVO.setTemplateParam(JsonUtil.objectToJson(valuesMap));

        //记录日志用
        smsSendVO.setTemplateId(smsTemplate.getId());
        smsSendVO.setServiceType(smsTemplate.getServiceCode());

        // 发送短信
        this.send(smsSendVO);
    }

    private void send(SmsSendVO smsSendVO) {

        SmsPlatform sendEvent = smsFactory.getSmsPlatform();
        debugger.log("找到短信插件:", sendEvent.getPluginName());

        Map config = this.getConfig();
        boolean result = sendEvent.onSend(smsSendVO, config);

        if(result){
            sendEvent.insertRecord(smsSendVO, config);
            logger.debug("已发送短信:短信内容为:" + smsSendVO.getContent() + "手机号:" + smsSendVO.getMobile());
        }

    }

    @Override
    public boolean valid(String scene, String mobile, String code) {
        //从传入参数组织key
        String valCode = CachePrefix.SMS_CODE.getPrefix() + scene + "_" + mobile;
        //redis中获取验证码
        Object obj = cache.get(valCode);
        if (obj != null && obj.equals(code)) {
            //验证码校验通过后清除缓存
            cache.remove(valCode);
            //将标识放入缓存中，在验证验证码正确后，下一步操作需要校验是否经过验证验证码(缓存中是否存在)
            cache.put(CachePrefix.MOBILE_VALIDATE.getPrefix() + "_" + scene + "_" + mobile, mobile, erpConfig.getCaptchaTimout());
            return true;
        }
        return false;
    }

    @Override
    public String validMobile(String scene, String mobile) {
        String validMobile = (String) cache.get(CachePrefix.MOBILE_VALIDATE.getPrefix() + "_" + scene + "_" + mobile);
        if (!StringUtil.isEmpty(validMobile)) {
            return validMobile;
        }
        return null;
    }

    @Override
    public void record(String scene, String mobile, String code) {
        cache.put(CachePrefix.SMS_CODE.getPrefix() + scene + "_" + mobile, code, erpConfig.getSmscodeTimout());
    }

    @Override
    public void sendSmsMessage(String byName, String mobile, SceneType sceneType) {

        StringBuffer num = new StringBuffer();
        num.append(CachePrefix.PHONE_SMS_NUMBER.getPrefix());
        num.append(mobile);
        num.append(sceneType);

        String siteSettingJson = settingManager.get(SettingGroup.SITE);
        SiteSetting siteSetting = JsonUtil.jsonToObject(siteSettingJson, SiteSetting.class);
        //true:开启了测试模式
        boolean isOpenTest = siteSetting.getTestMode().equals(1);

        //根据验证码业务类型，获取对应的短信模板
        SmsServiceCodeEnum smsServiceCodeEnum = getServiceCode(sceneType);
        // 随机生成的动态码
        String dynamicCode;

        //如果是测试模式
        if (isOpenTest) {
            //验证码为1111
            dynamicCode = "1111";

            //如果未开启测试模式
        } else {
            //随机生成动态码
            dynamicCode = RandomCreate.getRandomCode();

            //开启时间间隔判断
            Object o = cache.get(num.toString());
            if (o != null) {
                throw new ServiceException(SystemErrorCode.E904.code(), "发送短信频繁，请稍后再试");
            }
            cache.put(num.toString(), "1", 60);

            //判断模板是否开启，查询当前开启的验证码模板
            SmsTemplate smsTemplate = smsTemplateManager.getOpenTemplate(smsServiceCodeEnum);
            //并且模板不是开启状态，则提示无法发送短信
            if(smsTemplate == null || EnableStatusEnum.CLOSE.value().equals(smsTemplate.getEnableStatus())){
                throw new ServiceException(SystemErrorCode.E904.code(), "未找到可用的短信模板，无法发送短信，请联系管理员开启");
            }
        }

        //短信模板参数变量
        Map<String, Object> valuesMap = new HashMap<>(4);
        valuesMap.put("code", dynamicCode);

        SmsSendMsg smsSendMsg = new SmsSendMsg();
        smsSendMsg.setPhoneNumber(mobile);
        smsSendMsg.setServiceCode(smsServiceCodeEnum);
        smsSendMsg.setValuesMap(valuesMap);

        //发送短信验证码
        messageSender.send(new MqMessage(AmqpExchange.SEND_MESSAGE, AmqpExchange.SEND_MESSAGE + "_QUEUE",
                smsSendMsg));

        //缓存中记录验证码
        this.record(sceneType.name(), mobile, dynamicCode);
    }

    private SmsServiceCodeEnum getServiceCode(SceneType sceneType) {

        if(SceneType.LOGIN.equals(sceneType)){
            return SmsServiceCodeEnum.MOBILECODESEND_LOGIN;
        }

        throw new ServiceException(SystemErrorCode.E904.code(), "未找到对应的短信模板，请联系管理员");
    }

    protected String getSendMessageExchange() {
        return AmqpExchange.SEND_MESSAGE;
    }

    private String replaceContent(String templateContent, Map<String, Object> valuesMap) {
        StrSubstitutor strSubstitutor = new StrSubstitutor(valuesMap);
        return strSubstitutor.replace(templateContent);
    }

    /**
     * 将json参数转换为map格式
     *
     * @return 短信参数
     */
    private Map getConfig() {
        SmsPlatformVO smsPlatformVO = (SmsPlatformVO) this.cache.get(getSmsPlatformKey());

        if (StringUtil.isEmpty(smsPlatformVO.getConfig())) {
            return new HashMap<>(16);
        }
        Gson gson = new Gson();
        List<ConfigItem> list = gson.fromJson(smsPlatformVO.getConfig(), new TypeToken<List<ConfigItem>>() {
        }.getType());
        Map<String, String> result = new HashMap<>(16);
        if (list != null) {
            for (ConfigItem item : list) {
                result.put(item.getName(), StringUtil.toString(item.getValue()));
            }
        }
        return result;

    }

    protected String getSmsPlatformKey() {
        return CachePrefix.SPlATFORM.getPrefix();
    }
}
