package com.iformall.schedule;

import com.alibaba.fastjson.JSONObject;
import com.iformall.common.ErrorCode;
import com.iformall.domain.dto.WxCUserBasicInfoDto;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxCouponSendVo;
import com.iformall.enums.EnumCouponSendSendType;
import com.iformall.enums.EnumCouponSendStatus;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.service.WxCouponActionLogService;
import com.iformall.service.WxCouponSendService;
import com.iformall.service.WxLevelConfigService;
import com.iformall.service.WxOrderService;
import io.swagger.models.auth.In;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class CouponSendSchedule {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private WxMallMapper wxMallMapper;

    @Autowired
    private WxLevelConfigMapper WxLevelConfigMapper;

    @Autowired
    private WxLevelConfigService wxLevelConfigService;

    @Autowired
    private WxCUserBasicInfoMapper wxCUserBasicInfoMapper;

    @Autowired
    private WxCouponSendMapper wxCouponSendMapper;

    @Autowired
    private WxCouponActionLogMapper wxCouponActionLogMapper;

    @Autowired
    private WxOrderService wxOrderService;

    @Autowired
    private WxCouponActionLogService wxCouponActionLogService;


    //@Scheduled(cron = "0 0 6 1 * ?") // 每月1号发放会员的权益券
    @Scheduled(cron = "0 0 6 * * ?") // 测试每天6点发券
    //@Scheduled(cron = "*/30 * * * * ?") // 测试30秒中一次
    public void couponSendSchedule() {

        List<WxMall> mallList = wxMallMapper.findList(new WxMall());

        if (mallList.size()==0) {
            logger.info("定时发券: No Mall info found");
            return;
        }

        Date startTime = Date.from(LocalDateTime.now()
                .with(TemporalAdjusters.firstDayOfMonth())
                .with(LocalTime.MIN)
                .atZone(ZoneId.systemDefault())
                .toInstant());
        Date endTime = Date.from(LocalDateTime.now()
                .with(TemporalAdjusters.lastDayOfMonth())
                .with(LocalTime.MAX)
                .atZone(ZoneId.systemDefault())
                .toInstant());

        mallList.stream().forEach(mall-> {

            WxLevelConfig wxLevelConfig = new WxLevelConfig();
            wxLevelConfig.setTenantId(mall.getTenantId());
            List<WxLevelConfig> levelConfigList = WxLevelConfigMapper.findList(wxLevelConfig);
            levelConfigList = levelConfigList.stream()
                    .sorted(Comparator.comparing(WxLevelConfig::getPoints))
                    .collect(Collectors.toList());

            for (int levelIndex = 0; levelIndex < levelConfigList.size(); levelIndex++) {
                WxLevelConfig l = levelConfigList.get(levelIndex);
                if (l.getCapability() == null)
                    continue;
                Integer levelStartScore = l.getPoints();
                Integer levelEndScore = levelIndex+1 < levelConfigList.size() ? levelConfigList.get(levelIndex+1).getPoints() : null;

                JSONObject jo = null;
                Long result = null;
                try {
                    jo = JSONObject.parseObject(l.getCapability());
                    result = wxLevelConfigService.getCapabilitiesOfSendCarConpon(jo);
                } catch (Exception e) {
                    logger.error("定时发券: 不能解析发券规则 levelId=" + l.getId() + e.getMessage());
                    continue;
                }
                Long sendCount = result;
                if (sendCount > 0) {

                    WxCUserBasicInfoDto wxCUserBasicInfoDto = new WxCUserBasicInfoDto();
                    wxCUserBasicInfoDto.setTenantId(l.getTenantId());
                    wxCUserBasicInfoDto.setLevelStartScore(levelStartScore);
                    wxCUserBasicInfoDto.setLevelEndScore(levelEndScore);
                    List<WxCUserBasicInfo> wxCUserBasicInfoList = wxCUserBasicInfoMapper.findListByScore(wxCUserBasicInfoDto);

                    logger.info("定时发券:给LEVEL["+ l.getLevel() +
                            "]积分["+levelStartScore+"-"+levelEndScore+"]发券"+sendCount+"张");

                    wxCUserBasicInfoList.stream().forEach(cu->{

                        WxCouponSend wxCouponSend = new WxCouponSend();
                        wxCouponSend.setTenantId(l.getTenantId());
                        wxCouponSend.setSendType(EnumCouponSendSendType.TIMED.getCode());
                        wxCouponSend.setStatus(EnumCouponSendStatus.VALID.getCode());
                        List<WxCouponSendVo> couponSendList = wxCouponSendMapper.findListVo(wxCouponSend);
                        int remain = couponSendList.stream().map(cs->{
                            int count = cs.getRemainInventory();
                            logger.info("定时发券:给["+ cu.getNickName() +
                                    "]券[" + cs.getTitle() + "]还剩" +
                                    count +"张");
                            return count;
                        }).reduce(Integer::sum).get();

                        if (remain < sendCount){
                            logger.error("定时发券:库存不足["+ cu.getNickName() +"]应发"+sendCount+"张,总共剩"+ remain + "张");
                            return;
                        }

                        int sentCount = couponSendList.stream().map(cs->{
                            Map params = new HashMap<String, Object>();
                            params.put("tenantId", cs.getTenantId());
                            params.put("cUserId", cu.getId());
                            params.put("couponId", cs.getCouponId());
                            params.put("startTime", startTime);
                            params.put("endTime", endTime);
                            params.put("channelType", EnumCouponSendSendType.TIMED.getCode());
                            int count =  wxCouponActionLogMapper.getCountByUserAndCouponAndDate(params);
                            logger.info("定时发券:已经给["+ cu.getNickName() +
                                    "]券[" + cs.getTitle() + "] " +
                                    count +"张");
                            return count;
                        }).reduce(Integer::sum).get();


                        logger.info("定时发券:给["+ cu.getNickName() +
                                "]总共已发送券" + sentCount + "张,还需发"+ (sendCount-sentCount) +"张");

                        for (int count = 0; count < sendCount - sentCount; count++) {
                            boolean sent = false;
                            for(int couponIndex = 0; couponIndex< couponSendList.size(); couponIndex++) {
                                WxCouponSendVo cs = couponSendList.get(couponIndex);
                                if (cs.getRemainInventory() <= 0)
                                    continue;

                                // 发放免费券
                                try {
                                    WxCouponOrder couponOrder = wxOrderService.sendFreeCouponToUser(cu.getId(), cs.getCouponId());
                                    wxCouponActionLogService.addOne(l.getTenantId(), cs.getCouponId(), couponOrder.getId(), cs.getSendType(), cs.getId());
                                } catch (Exception e) {
                                    logger.error("定时发券:发券失败 levelId=" + l.getId() + " couponId=" + cs.getCouponId() + " userId=" + cu.getId() + e.getMessage());
                                    continue;
                                }

                                logger.info("定时发券:商场[" + mall.getName() +
                                        "]会员等级[" + l.getLevel() +
                                        "]发送券[" + cs.getTitle() +
                                        "]给:" + cu.getNickName() +
                                        " 电话-" + cu.getPhone() +
                                        " id-" + cu.getId());
                                sent = true;
                                break;
                            }
                            if (!sent)
                                break;
                        }
                    });
                }
            }
        });
    }
}