package com.hai.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hai.common.exception.ErrorCode;
import com.hai.common.exception.ErrorHelp;
import com.hai.common.exception.SysCode;
import com.hai.common.security.UserCenter;
import com.hai.common.utils.DateUtil;
import com.hai.config.ChongQingCNPCService;
import com.hai.dao.HighCouponCodeMapper;
import com.hai.dao.HighCouponCodeOtherMapper;
import com.hai.dao.HighDiscountAgentCodeMapper;
import com.hai.dao.HighDiscountUserRelMapper;
import com.hai.entity.*;
import com.hai.model.DiscountUseConditionModel;
import com.hai.model.HighUserModel;
import com.hai.service.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Auther: 胡锐
 * @Description:
 * @Date: 2021/4/14 22:09
 */
@Service("highDiscountAgentCodeService")
public class HighDiscountAgentCodeServiceImpl implements HighDiscountAgentCodeService {

    @Resource
    private HighDiscountAgentCodeMapper highDiscountAgentCodeMapper;

    @Resource
    private HighDiscountUserRelMapper highDiscountUserRelMapper;

    @Resource
    private HighDiscountAgentRelService highDiscountAgentRelService;

    @Resource
    private HighCouponCodeMapper highCouponCodeMapper;

    @Resource
    private HighDiscountService highDiscountService;

    @Resource
    private HighAgentService highAgentService;

    @Resource
    private HighOrderService highOrderService;

    @Resource
    private HighUserService highUserService;

    @Resource
    private HighDiscountUserRelService highDiscountUserRelService;

    @Resource
    private HighCouponCodeOtherMapper highCouponCodeOtherMapper;

    @Resource
    private HighDiscountCouponRelService highDiscountCouponRelService;

    @Resource
    private UserCenter userCenter;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private SecConfigService secConfigService;

    @Override
    public void insertCodeList(List<HighDiscountAgentCode> discountAgentCodeList) {
        highDiscountAgentCodeMapper.insertListCode(discountAgentCodeList);
    }

    @Override
    public void insertCode(HighDiscountAgentCode highDiscountAgentCode) {
        highDiscountAgentCodeMapper.insert(highDiscountAgentCode);
    }

    @Override
    public void updateCode(HighDiscountAgentCode highDiscountAgentCode) {
        highDiscountAgentCodeMapper.updateByPrimaryKey(highDiscountAgentCode);
    }

    @Override
    public List<HighDiscountAgentCode> getDiscountCode(Map<String, Object> map) {
        HighDiscountAgentCodeExample example = new HighDiscountAgentCodeExample();
        HighDiscountAgentCodeExample.Criteria criteria = example.createCriteria();

        if (MapUtils.getLong(map, "discountAgentId") != null) {
            criteria.andDiscountAgentIdEqualTo(MapUtils.getLong(map, "discountAgentId"));
        }

        if (MapUtils.getInteger(map, "status") != null) {
            criteria.andStatusEqualTo(MapUtils.getInteger(map, "status"));
        }

        example.setOrderByClause("create_time desc");
        List<HighDiscountAgentCode> list = highDiscountAgentCodeMapper.selectByExample(example);
        for (HighDiscountAgentCode code : list) {
            HighDiscountAgentRel rel = highDiscountAgentRelService.getRelById(code.getDiscountAgentId());
            if (rel != null) {
                code.setHighDiscount(highDiscountService.getDiscountById(rel.getDiscountId()));
                code.setHighAgent(highAgentService.findByAgentMsgId(rel.getAgentId()));
            }

            HighDiscountUserRel userRel = highDiscountUserRelService.getRelByDiscount(code.getId());
            if (userRel != null) {
                code.setHighUser(highUserService.findByUserId(userRel.getUserId()));
                code.setHighCouponCode(highCouponCodeMapper.selectCouponCodeByUserDiscount(userRel.getId()));
            }
        }
        return list;
    }

    @Override
    public List<DiscountUseConditionModel> getDiscountUseConditionList(Map<String, Object> map) throws Exception {
        if (MapUtils.getLong(map, "receiveTimeS") != null) {
           map.put("receiveTimeS", DateUtil.date2String(new Date(MapUtils.getLong(map, "receiveTimeS")), "yyyy-MM-dd HH:mm:ss"));
        }
        if (MapUtils.getLong(map, "receiveTimeE") != null) {
            map.put("receiveTimeE", DateUtil.date2String(new Date(MapUtils.getLong(map, "receiveTimeE")), "yyyy-MM-dd HH:mm:ss"));
        }

        if (MapUtils.getLong(map, "useTimeS") != null) {
            map.put("useTimeS", DateUtil.date2String(new Date(MapUtils.getLong(map, "useTimeS")), "yyyy-MM-dd HH:mm:ss"));
        }
        if (MapUtils.getLong(map, "useTimeE") != null) {
            map.put("useTimeE", DateUtil.date2String(new Date(MapUtils.getLong(map, "useTimeE")), "yyyy-MM-dd HH:mm:ss"));
        }

        return highDiscountAgentCodeMapper.getDiscountUseConditionList(map);
    }

    @Override
    public List<HighDiscountAgentCode> getDiscountCodeByDiscountAgentId(Long discountAgentId) {

        HighDiscountAgentCodeExample example = new HighDiscountAgentCodeExample();
        HighDiscountAgentCodeExample.Criteria criteria = example.createCriteria();
        criteria.andDiscountAgentIdEqualTo(discountAgentId).andStatusEqualTo(5);
        example.setOrderByClause("create_time desc");
        return highDiscountAgentCodeMapper.selectByExample(example);
    }

    @Override
    public List<HighDiscountAgentCode> getDiscountCodeByStatus(Long discountAgentId, Integer status) {
        HighDiscountAgentCodeExample example = new HighDiscountAgentCodeExample();
        HighDiscountAgentCodeExample.Criteria criteria = example.createCriteria();
        criteria.andDiscountAgentIdEqualTo(discountAgentId).andStatusEqualTo(status);
        example.setOrderByClause("create_time desc");
        return highDiscountAgentCodeMapper.selectByExample(example);
    }

    @Override
    public HighDiscountAgentCode getCodeById(Long id) {
        return highDiscountAgentCodeMapper.selectByPrimaryKey(id);
    }


    @Override
    public Integer getTotalDiscount(Long discountAgentId) {
        HighDiscountAgentCodeExample example = new HighDiscountAgentCodeExample();
        example.createCriteria().andDiscountAgentIdEqualTo(discountAgentId);
        return highDiscountAgentCodeMapper.selectByExample(example).size();
    }

    @Override
    public Integer getSalesDiscount(Long discountAgentId) {
        HighDiscountAgentCodeExample example = new HighDiscountAgentCodeExample();
        example.createCriteria().andDiscountAgentIdEqualTo(discountAgentId).andStatusNotEqualTo(1);
        return highDiscountAgentCodeMapper.selectByExample(example).size();
    }

    @Override
    public List<HighDiscountAgentCode> getDiscountAgentCodByLimit(Long discountAgentId, Long num) throws Exception {
        String key = "give_discount" + discountAgentId;
        try {
            // 分布式锁占坑
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, discountAgentId);
            if(lock) {

                List<HighDiscountAgentCode> list = highDiscountAgentCodeMapper.getDiscountAgentCodByLimit(discountAgentId,num);

                if (list.size() < num) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "库存不足！");
                }

                return highDiscountAgentCodeMapper.getDiscountAgentCodByLimit(discountAgentId,num);
            } else {
                // 加锁失败，重试
                Thread.sleep(100);
                getDiscountAgentCodByLimit(discountAgentId , num);
            }
        }catch (Exception e) {
            throw e;
        } finally {
            // 删除key，释放锁
            redisTemplate.delete(key);
        }

        return null;
    }

    @Override
    @Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRES_NEW, timeout = 30)
    public void useDiscount(Long discountAgentCodeId) throws Exception {
        HighUserModel userModel = userCenter.getSessionModel(HighUserModel.class);
        if (userModel == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.SEC_USER_EXPIRED, "");
        }
        if (StringUtils.isBlank(userModel.getHighUser().getPhone())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "客户未设置手机号");
        }
        // 查询优惠券code
        HighDiscountAgentCode discountAgentCode = getCodeById(discountAgentCodeId);
        if (discountAgentCode == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "优惠券code错误");
        }
        if (!discountAgentCode.getStatus().equals(2)) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "优惠券状态错误");
        }
        HighDiscountUserRel discountUserRel = highDiscountUserRelService.getRelByAgentCodeId(discountAgentCodeId);
        if (discountUserRel != null) {
            if (!userModel.getHighUser().getId().equals(discountUserRel.getUserId())) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "无法使用，领取人和使用人不一致。");
            }
        }
        String key = "DiscountAgentId_" + discountAgentCode.getDiscountAgentId();
        try {
            // 分布式锁占坑
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, discountAgentCode.getId());
            if(lock) {
                if (StringUtils.isBlank(discountAgentCode.getExt2())) {
                    HighDiscountAgentRel rel = highDiscountAgentRelService.getRelById(discountAgentCode.getDiscountAgentId());
                    if (rel == null) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到代理商关联关系");
                    }
                    HighDiscount discount = highDiscountService.getDiscountById(rel.getDiscountId());
                    if (discount == null) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到优惠券");
                    }
                    List<HighDiscountCouponRel> couponRelList = highDiscountCouponRelService.getRelByDiscount(discount.getId());
                    if (couponRelList.size() == 0) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "优惠券未配置卡券");
                    }
                    List<HighDiscountCouponRel> couponList = couponRelList.stream().filter(o -> o.getHighCoupon().getCouponSource().equals(5)).collect(Collectors.toList());
                    if (couponList.size() == 0) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "优惠券未配置重庆中石油卡券");
                    }
                    // 重庆中石油业务状态
                    SecConfig cqCnpcStatus = secConfigService.findByCodeType("CQ_CNPC_STATUS_" + couponList.get(0).getHighCoupon().getCouponKey());
                    if (cqCnpcStatus != null && StringUtils.isNotBlank(cqCnpcStatus.getCodeValue())) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, cqCnpcStatus.getCodeValue());
                    }
                    String tradeId = discountAgentCode.getId()+""+System.currentTimeMillis()+"";
                    // 预发码
                    JSONObject preSendCoupon = ChongQingCNPCService.preSendCoupon(couponList.get(0).getHighCoupon().getCouponKey(), tradeId, 1, userModel.getHighUser().getPhone());
                    if (!preSendCoupon.getInteger("status").equals(1)) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "领取优惠券失败，请稍后重试");
                    }
                    // 给用户发码
                    JSONObject response = ChongQingCNPCService.sendCNPCTicket(
                            couponList.get(0).getHighCoupon().getCouponKey(),
                            tradeId,
                            1,
                            userModel.getHighUser().getPhone());
                    JSONObject couponDetail = response.getJSONObject("ticketDetail");
                    JSONArray codeList = response.getJSONArray("codeList");

                    for (Object data : codeList) {
                        HighCouponCodeOther couponCodeOther = new HighCouponCodeOther();
                        couponCodeOther.setType(3);
                        couponCodeOther.setDiscountAgentCodeId(discountAgentCode.getId());
                        couponCodeOther.setCouTypeCode(couponDetail.getString("requestCode"));
                        couponCodeOther.setCouNo(ChongQingCNPCService.decryptCouponCode(String.valueOf(data)));
                        couponCodeOther.setActiveTime(new Date());
                        couponCodeOther.setValidStartDate(DateUtil.format(couponDetail.getString("effectiveTime"), "yyyy-MM-dd"));
                        couponCodeOther.setValidEndDate(DateUtil.format(couponDetail.getString("expiredDate"), "yyyy-MM-dd"));
                        couponCodeOther.setStatus(20);
                        couponCodeOther.setCreateTime(new Date());
                        highCouponCodeOtherMapper.insert(couponCodeOther);
                    }
                    discountAgentCode.setExt2(tradeId);
                    updateCode(discountAgentCode);
                }
            } else {
                // 加锁失败，重试
                Thread.sleep(100);
                useDiscount(discountAgentCodeId);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            // 删除key，释放锁
            redisTemplate.delete(key);
        }
    }

    @Override
    public void giveDiscount(Long discountAgentId, Long num, Long userId) throws Exception {
        // 查询可以使用的优惠券
        List<HighDiscountAgentCode> discountAgentCodeList = getDiscountAgentCodByLimit(discountAgentId , num);

        if (discountAgentCodeList == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "库存不足！");
        }

        HighDiscountAgentRel discountAgentRel = highDiscountAgentRelService.getRelById(discountAgentId);

        HighDiscount discount  = highDiscountService.getDiscountById(discountAgentRel.getDiscountId());
        // 优惠券
        for (HighDiscountAgentCode discountAgentCode : discountAgentCodeList) {

            HighDiscountUserRel highDiscountUserRel = new HighDiscountUserRel();
            highDiscountUserRel.setDiscountId(discountAgentRel.getDiscountId());
            highDiscountUserRel.setUserId(userId);
            highDiscountUserRel.setAgentId(discountAgentRel.getAgentId());
            highDiscountUserRel.setDiscountAgentCodeId(discountAgentCode.getId());
            highDiscountUserRel.setStatus(1);
            highDiscountUserRel.setCreateTime(new Date());
            highDiscountUserRel.setDiscountCompanyId(discount.getCompanyId());
            highDiscountUserRel.setDiscountUseScope(discount.getUseScope());
            highDiscountUserRel.setDiscountUsingRange(discount.getUsingRange());
            highDiscountUserRel.setDiscountCondition(discount.getDiscountCondition());
            highDiscountUserRel.setDiscountType(discount.getDiscountType());
            highDiscountUserRel.setDiscountImg(discount.getDiscountImg());
            highDiscountUserRel.setDiscountName(discount.getDiscountName());
            highDiscountUserRel.setDiscountCondition(discount.getDiscountCondition());
            highDiscountUserRel.setDiscountPrice(discount.getDiscountPrice());

            // 计算使用有效期
            Calendar userEndTime = Calendar.getInstance();
            userEndTime.setTime(new Date());
            userEndTime.set(Calendar.HOUR_OF_DAY, 23);
            userEndTime.set(Calendar.MINUTE, 59);
            userEndTime.set(Calendar.SECOND, 59);
            userEndTime.add(Calendar.DATE, discount.getEffectiveDay());
            highDiscountUserRel.setUseEndTime(userEndTime.getTime());

            // 新增优惠券与用户的绑定关系
            highDiscountUserRelMapper.insert(highDiscountUserRel);

            // 修改优惠券二维码状态
            discountAgentCode.setStatus(2);
            updateCode(discountAgentCode);

        }

    }
}
