package cn.axzo.msg.center.notices.manager;

import cn.axzo.msg.center.domain.entity.MNSMessageChannelLog;
import cn.axzo.msg.center.notices.common.domain.ServiceContext;
import cn.axzo.msg.center.notices.common.domain.ServiceContextHolder;
import cn.axzo.msg.center.notices.common.enums.ChannelHandlerEnum;
import cn.axzo.msg.center.notices.common.enums.ReturnCodeEnum;
import cn.axzo.msg.center.notices.common.exception.BizException;
import cn.axzo.msg.center.notices.manager.api.SmsSendManager;
import cn.axzo.msg.center.notices.manager.api.dto.response.BatchMessageSendResponseDto;
import cn.axzo.msg.center.notices.manager.api.dto.response.SendSmsCommonResponseDto;
import cn.axzo.msg.center.notices.manager.api.dto.request.BatchMessageSendRequestDto;
import cn.axzo.msg.center.notices.manager.api.dto.request.MessageSendRequestDto;
import cn.azxo.framework.common.utils.LogUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

/**
 * 消息发送聚合类
 *
 * @author zhaoyong
 * @see SmsSendManagerComposite
 * @since 2021-08-19 10:51
 */
@Slf4j
@Component("smsSendManagerComposite")
public class SmsSendManagerComposite implements SmsSendManager, ApplicationContextAware {

  private ApplicationContext applicationContext;

  @Override
  public SendSmsCommonResponseDto sendMessage(MessageSendRequestDto request) {
    // 根据渠道码获取实现类
    ChannelHandlerEnum handler = ChannelHandlerEnum.getByCode(request.getChannelCode());
    BizException.error(handler != null, ReturnCodeEnum.SYSTEM_ERROR,
        "不支持的渠道码:" + request.getChannelCode());

    SmsSendManager sendManager = applicationContext.getBean(handler.getMessage(), SmsSendManager.class);

    // 渲染请求
    renderRequest(request);

    // 服务上下文
    ServiceContextHolder.set(new ServiceContext());

    try {
      // 发送短信
      SendSmsCommonResponseDto response = sendManager.sendMessage(request);

      // 保存渠道日志
      saveMessageChannelLog(request, ServiceContextHolder.get().getChannelResponse());

      // 响应结果
      return response;
    } catch (BizException e) {
      LogUtil.error("SmsSendManagerComposite#sendMessage is BizException", e);
      // 保存渠道日志
      saveMessageChannelLog(request, e);
      throw e;
    } catch (Exception e) {
      log.warn("SmsSendManagerComposite#sendMessage is Exception", e);
      LogUtil.error("SmsSendManagerComposite#sendMessage is Exception", e);
      // 保存渠道日志
      saveMessageChannelLog(request, e.getMessage());
      throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "system error");
    } finally {
      ServiceContextHolder.cleanUp();
    }
  }

  @Override
  public BatchMessageSendResponseDto sendBatchMessage(BatchMessageSendRequestDto requestDto) {
    // 指定渠道
    ChannelHandlerEnum handler = ChannelHandlerEnum.CHUANG_LAN;

    // 根据渠道码获取实现类
    SmsSendManager smsSendManager = applicationContext.getBean(handler.getMessage(), SmsSendManager.class);

    // 服务上下文
    ServiceContextHolder.set(new ServiceContext());
    try {
      // 发送短信
      BatchMessageSendResponseDto response = smsSendManager.sendBatchMessage(requestDto);

      // 保存渠道日志
      saveMessageChannelLog(requestDto, ServiceContextHolder.get().getChannelResponse());

      // 响应结果
      return response;
    } catch (BizException e) {
      LogUtil.error("SmsSendManagerComposite#sendBatchMessage is BizException", e);
      // 保存渠道日志
      saveMessageChannelLog(requestDto, e);
      throw e;
    } catch (Exception e) {
      LogUtil.error("SmsSendManagerComposite#sendBatchMessage is Exception", e);
      // 保存渠道日志
      saveMessageChannelLog(requestDto, e.getMessage());
      throw new BizException(ReturnCodeEnum.SYSTEM_ERROR, "system error");
    } finally {
      ServiceContextHolder.cleanUp();
    }
  }

  /**
   * 渲染请求
   * @param request
   */
  private void renderRequest(MessageSendRequestDto request) {
    // 获取模板参数
    Map<String, Object> templateMap = request.getTemplateMap();

    // 处理短信字符串变量参数超长问题
    Map<String, Object> renderTemplateMap = handleSmsParamsSize(templateMap);

    // 修改模板参数
    request.setTemplateMap(renderTemplateMap);
  }

  /**
   * 处理短信字符串变量参数超长问题
   * @param templateMap
   * @return
   */
  private Map<String, Object> handleSmsParamsSize(Map<String, Object> templateMap) {
    if (CollectionUtils.isEmpty(templateMap)){
      return templateMap;
    }
    Iterator<Entry<String, Object>> entries = templateMap.entrySet().iterator();

    while (entries.hasNext()) {
      Entry<String, Object> entry = entries.next();
      Object value = entry.getValue();
      String key = entry.getKey();
      if (Objects.nonNull(value)){
        if (value instanceof String){
          String handledStr = handleSmsVariableSize(String.valueOf(value));
          templateMap.put(key,handledStr);
        }
      }
    }
    return templateMap;
  }

  /**
   * 处理短信参数长度
   * @param str
   * @return
   */
  private String handleSmsVariableSize(String str) {
    if (str != null) {
      int size = str.length();
      if ( size <= 35 ) {
        return str;
      }
      return str.substring(0, 32) + "...";
    }
    return "";
  }

  /**
   * 保存单条短信渠道日志
   * @param requestDto
   * @param response
   * @param response
   */
  private void saveMessageChannelLog(MessageSendRequestDto requestDto, Object response) {
    MNSMessageChannelLog log = new MNSMessageChannelLog();
    log.setAppNo(requestDto.getAppCode());
    log.setAppRequestNo(requestDto.getAppRequestNo());
    log.setMessageOrderNo(requestDto.getRequestChannelNo());
    log.setTargetAddress(requestDto.getPhoneNo());
    log.setUpdateAt(new Date());
    log.setCreateAt(new Date());
    String responseData = getResponseData(response);
    log.setResponseData(responseData);
    log.insert();
  }



  /**
   * 保存批量短信渠道日志
   * @param requestDto
   * @param response
   */
  private void saveMessageChannelLog(BatchMessageSendRequestDto requestDto, Object response) {
    MNSMessageChannelLog log = new MNSMessageChannelLog();
    log.setAppNo(requestDto.getAppCode());
    log.setAppRequestNo(requestDto.getAppRequestNo());
    log.setMessageOrderNo(requestDto.getRequestChannelNo());
    log.setTargetAddress(requestDto.getMessageKey());
    log.setUpdateAt(new Date());
    log.setCreateAt(new Date());
    String responseData = getResponseData(response);
    log.setResponseData(responseData);
    log.insert();
  }

  /**
   * 获取响应数据
   * @param response
   * @return
   */
  private String getResponseData(Object response){
    if(response instanceof BizException) {
      BizException exception = BizException.class.cast(response);
      if(exception.getData() != null) {
        return JSON.toJSONString(exception.getData());
      } else {
        return JSON.toJSONString(exception.getMessage());
      }
    } else {
      return JSON.toJSONString(response);
    }
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
}
