package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxCUserBasicInfoFilterDto;
import com.iformall.domain.dto.WxCUserBasicInfoFilterListDto;
import com.iformall.domain.po.*;
import com.iformall.domain.po.msg.WxMsg;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.WxCouponInjectMapper;
import com.iformall.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WxCouponInjectServiceImpl implements WxCouponInjectService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxCouponInjectMapper couponInjectMapper;

    @Autowired
    WxCouponOrderService wxCouponOrderService;

    @Autowired
    WxCouponService wxCouponService;

    @Autowired
    WxCUserBasicInfoService wxCUserBasicInfoService;

    @Autowired
    WxCUserService wxCUserService;

    @Autowired
    WxCouponActionLogService wxCouponActionLogService;

    @Autowired
    WxMsgService wxMsgService;

    @Autowired
    WxMsgModelService wxMsgModelService;

    @Autowired
    WxMsgConfigService wxMsgConfigService;

    @Autowired
    PushLimitService pushLimitService;

    @Autowired
    WxOrderService wxOrderService;


    @Override
    public PageInfo<WxCouponInject> listAsPage(WxCouponInject record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> couponInjectMapper.findList(record));
    }

    @Override
    public WxCouponInject getById(Long id) {
        return couponInjectMapper.selectById(id);
    }

    @Override
    public void saveOrUpdate(WxCouponInject record) {
        Date curDate = new Date();
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            record.setCreateTime(curDate);
            record.setUpdateTime(curDate);
            couponInjectMapper.insert(record);
        } else {
            record.setUpdateTime(curDate);
            couponInjectMapper.updateById(record);
        }
    }

    @Override
    public void deleteById(Long id) {
        couponInjectMapper.deleteById(id);
    }

    @Override
    public ResultData add(WxCouponInject record) {

        try {
            pushLimitService.checkSendTime(record.getTenantId());
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(),e.getMessage());
        }

        WxCoupon wxCoupon = wxCouponService.getById(record.getCouponId());
        if (wxCoupon.getValidType().equals(EnumCouponValidType.BETWEEN_TWO_TIME.getCode()) ) { //时间范围
            if (new Date().after(wxCoupon.getValidEndDate())) {
                return new ResultData(ErrorCode.COUPON_IS_EXPIRED);
            }
        }
        if(!wxCoupon.getStatus().equals(EnumCouponStatus.COUPON_STATUS_THROW_IN.getCode())){
            return new ResultData(ErrorCode.COUPON_IS_TAKE_OFF);
        }
        if(!wxCoupon.getSendType().equals(EnumCouponSendType.PASSIVE.getCode())) {
            return new ResultData(ErrorCode.COUPON_TYPE_IS_NOT_PASSIVE);
        }

        //1、手机多条以逗号分隔，直接通过实体得到wxmsg.getphones
        //2、通过标签
        String phones = record.getPhones();
        List<WxCUserBasicInfoFilterListDto> filter = record.getFilterList();
        if (!phones.isEmpty() && !filter.isEmpty()) {//两种方式只能选其一
            return new ResultData(ErrorCode.MSG_SEND_WAY_CHOOSE_ERROR);
        }
        if (phones.isEmpty() && filter.isEmpty()) {//两种方式必须选其一
            return new ResultData(ErrorCode.MSG_SEND_WAY_CHOOSE_ERROR);
        }

        if (!phones.isEmpty()) {//有手工输入手机号时解析
            String[] phoneSplit = phones.split(",");
            Set<String> phoneSet = new HashSet<>(Arrays.asList(phoneSplit));
            WxCUserBasicInfoFilterDto tag = new WxCUserBasicInfoFilterDto();
            tag.setTypeId(EnumTagType.ID_0.getCode());
            tag.setParam(StringUtils.join(phoneSet,","));
            WxCUserBasicInfoFilterListDto filterListDto = new WxCUserBasicInfoFilterListDto();
            filterListDto.setName(tag.getParam());
            filterListDto.setTagList(new ArrayList<WxCUserBasicInfoFilterDto>(){{add(tag);}});
            record.setFilterList(new ArrayList<WxCUserBasicInfoFilterListDto>(){{add(filterListDto);}});
        }
        record.setTags(JSON.toJSONString(record.getFilterList()));
        List<WxCUserBasicInfo> userList =
                wxCUserBasicInfoService.listByFilterList(record.getTenantId(),record.getFilterList());

        if(userList.isEmpty()){
            return new ResultData(ErrorCode.TAGS_MATCHED_NULL);
        }

        int inventory = wxCoupon.getRemainInventory();//库存数量
        if(userList.size()>inventory){
            return new ResultData(ErrorCode.COUPON_IS_SELL_OUT);
        }


        //生成雪花id
        final IdWorker idWorker = IdWorker.get();
        record.setId(idWorker.nextId());
        if(record.getSendType().equals(EnumCouponInjectSendType.IMMEDIATE.getCode())){
            record.setStatus(EnumCouponInjectStatus.SENDING.getCode());
            record.setSendTime(new Date());
        }else{
            record.setStatus(EnumCouponInjectStatus.PENDING.getCode());
        }

        record.setCouponName(wxCoupon.getTitle());
        record.setSendAmount(userList.size());

        couponInjectMapper.insert(record);
        if(record.getSendType().equals(EnumCouponInjectSendType.IMMEDIATE.getCode())) {
            List<WxCUser> sentUsers = sendCoupon(wxCoupon, userList, record);
            if (sentUsers.size() > 0) {
                record.setStatus(EnumCouponInjectStatus.HAS_SENT.getCode());
                //发送短信
                sendMsg(record, sentUsers);
            } else {
                record.setStatus(EnumCouponInjectStatus.SEND_FAILED.getCode());
            }
            record.setSendAmount(sentUsers.size());
            couponInjectMapper.updateById(record);
        }

        return new ResultData();
    }

    private ResultData sendMsg(WxCouponInject record, List<WxCUser> cUsers) {

        //根据模板ID查询短信信息
        WxMsgModel model = wxMsgModelService.getById(record.getModelId());
        if(model==null){
            return new ResultData(ErrorCode.MSG_TEMPLATE_NOT_FOUND);
        }

        WxMsg wxmsg=new WxMsg();
        wxmsg.setTenantId(record.getTenantId());
        WxMsgConfig wxMsgConfig = new WxMsgConfig();
        wxMsgConfig.setTenantId(wxmsg.getTenantId());
        wxMsgConfig = wxMsgConfigService.findObject(wxMsgConfig);
        if (wxMsgConfig==null){
            return new ResultData(ErrorCode.MSG_SERVER_NOT_FIND);
        }

        if(wxMsgConfig.getRemains()==0){
            return new ResultData(ErrorCode.MSG_SUM_ZERO);
        }

        //预计发送数量
        wxmsg.setExpectSendNumber(cUsers.size());
        if(wxMsgConfig.getRemains()<cUsers.size()){
            return new ResultData(ErrorCode.MSG_SUM_INSUFFICENT);
        }

        //获取手机号
        if(cUsers.size()==0){
            return new ResultData(ErrorCode.MSG_NO_VALID_PHONE);
        }
        StringBuffer sb=new StringBuffer();
        for(WxCUser user:cUsers){
            String phone  = user.getPhone();
            if(null!=phone && !phone.equals("")){
                sb.append(phone).append(",");
            }
        }
        wxmsg.setPhones(sb.deleteCharAt(sb.length()-1).toString());
        if(wxmsg.getPhones().equals("")){
            return new ResultData(ErrorCode.MSG_NO_VALID_PHONE);
        }

        //立即发送
        wxmsg.setIsright(EnumMsgSend.MSG_SEND_IMMEDIATELY.getCode());
        wxmsg.setStatus(EnumMsgStatus.MSG_STATUS_SENDED.getCode());
        wxmsg.setSendtime(com.iformall.utils.DateUtils.getSystemTime("yyyy-MM-dd HH:mm:ss"));

        wxmsg.setModelId(record.getModelId());
        wxmsg.setMsg(model.getContent());
        wxmsg.setName(model.getName());
        wxmsg.setSignature(model.getSignature());
        wxmsg.setSuccessNumber(0);
        wxmsg.setErrorNumber(0);
        //1、标签短信2、精准发券
        wxmsg.setWay(EnumSendWay.COUPON.getCode());
        wxMsgService.sendMsgFromCouponInject(wxmsg,wxMsgConfig,record);
        return new ResultData();
    }

    private List<WxCUser>  sendCoupon(WxCoupon wxCoupon,List<WxCUserBasicInfo> cUsers,WxCouponInject record){

        //查询标签用户
        List<WxCUser> sentUsers = new ArrayList<WxCUser>();
        for (WxCUserBasicInfo tempCUserBasicInfo  : cUsers) {
            WxCUser tempCUser = wxCUserService.getById(tempCUserBasicInfo.getId());
            if (tempCUser != null) {
                boolean bResult = sendCouponToUser(tempCUser, wxCoupon, record.getId());
                if (bResult) {
                    sentUsers.add(tempCUser);
                }
            }
        }
        return sentUsers;
    }


    private boolean sendCouponToUser(WxCUser tempCUser,WxCoupon wxCoupon,Long couponInjectId) {
        boolean checkLimit = false;
        // 检查疲劳度
        try {
            checkLimit = pushLimitService.checkCoupon(tempCUser.getTenantId(), tempCUser.getId(), wxCoupon.getId());
        } catch (MallinkException e) {
            logger.error(e.getMessage());
        }
        if (!checkLimit) {
            return false;
        }
        // 发放免费券
        WxCouponOrder couponOrder = null;
        try {
            couponOrder = wxOrderService.sendFreeCouponToUser(tempCUser.getId(), wxCoupon.getId(),null);
            if (couponOrder != null) {
                wxCouponActionLogService.addOne(tempCUser.getTenantId(), wxCoupon.getId(), couponOrder.getId(), EnumCouponSendSendType.INJECT.getCode(), couponInjectId);
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return false;
        }

        return true;
    }


}
