package com.gree.mall.manager.logic.activity;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.manager.bean.activity.*;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.goods.CustomSecSpecBeanVO;
import com.gree.mall.manager.bean.goods.SecKillActivityStageBeanVO;
import com.gree.mall.manager.commonmapper.CommonPageV2Mapper;
import com.gree.mall.manager.commonmapper.SecKillMapper;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.zfire.bean.QueryParamBean;
import com.gree.mall.manager.zfire.bean.ZfireParamBean;
import com.gree.mall.manager.zfire.util.FieldUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

@Slf4j
@Component
public class SecKillLogic {

    @Resource
    SecKillActivityService secKillActivityService;
    @Resource
    SecKillActivitySpecService secKillActivitySpecService;
    @Resource
    SecKillStageService secKillStageService;
    @Resource
    CommonLogic commonLogic;
    @Autowired
    private GoodsSpecService goodsSpecService;
    @Autowired
    private RedisLockRegistry redisLockRegistry;
    @Autowired
    private SecKillMapper secKillMapper;
    @Value("${goods.share.limit.percent}")
    private String percentLimit;
    @Autowired
    private GoodsService goodsService;

    @Autowired
    CommonPageV2Mapper commonPageV2Mapper;

    public final static String LOCK_ORDER_STOCK = "gejiang:lock:stock";

    /**
     * 秒杀商品列表
     *
     * @param keyword
     * @param pageNum
     * @param pageSize
     * @return
     */
    public IPage<CustomSecSpecBean> pageSpec(Integer status, String keyword, Integer pageNum, Integer pageSize, HttpServletRequest request) {
        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        IPage<CustomSecSpecBean> customSecSpecBeanIPage = secKillMapper.querySecSpec(new Page(pageNum, pageSize), keyword, status,adminUser.getCompanyWechatIds());
        return customSecSpecBeanIPage;

    }

    public IPage<SecKillActivityStageBean> pageActivity(Integer status, String keyword, Date startTime, Integer pageNum, Integer pageSize,HttpServletRequest request) {
        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        IPage<SecKillActivityStageBean>  secKillActivityStageBeans = secKillMapper
                .queryActivity(new Page(pageNum,pageSize),status, keyword, startTime, adminUser.getCompanyWechatIds());
        return secKillActivityStageBeans;
    }

    /**
     * 新增秒杀商品
     *
     * @param secKillActivityBean
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(SecKillActivityBean secKillActivityBean,HttpServletRequest request) throws RemoteServiceException {
        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        String loginCompanyWechatId = adminUser.getCompanyWechatId();

        Integer count = secKillActivityService.lambdaQuery()
                .eq(SecKillActivity::getStatus, true)
                .eq(SecKillActivity::getDel, false)
                .and(o1 -> o1.between(SecKillActivity::getStartTime, secKillActivityBean.getStartTime(), secKillActivityBean.getEndTime())
                        .or(o2 -> o2.between(SecKillActivity::getEndTime, secKillActivityBean.getStartTime(), secKillActivityBean.getEndTime()))
                        .or(o3 -> o3
                                .lt(SecKillActivity::getStartTime,secKillActivityBean.getStartTime())
                                .gt(SecKillActivity::getEndTime,secKillActivityBean.getEndTime()))
                )
                .eq(SecKillActivity::getCompanyWechatId, loginCompanyWechatId)
                .count();
        if (count > 0) {
            throw new RemoteServiceException("活动时间不能重叠");
        }

        if (secKillActivityBean.getGoodsSpecs() != null) {
            for (SecKillActivitySpecBean secKillActivitySpecBean : secKillActivityBean.getGoodsSpecs()) {
                if (secKillActivitySpecBean.getLimitBuy() == null) {
                    throw new RemoteServiceException("限制购买数量不能为空");
                }
                if (secKillActivitySpecBean.getStockNum() == null) {
                    throw new RemoteServiceException("库存不能为空");
                }
                if (secKillActivitySpecBean.getStockNum() == 0) {
                    throw new RemoteServiceException("无效库存");
                }

                if (secKillActivitySpecBean.getPrice() == null) {
                    throw new RemoteServiceException("秒杀价格不能为空");
                }
                if (secKillActivitySpecBean.getPrice().compareTo(new BigDecimal(0.00)) <= 0) {
                    throw new RemoteServiceException("无效价格");
                }

                if (secKillActivitySpecBean.getGoodsSpecId() != null) {
                    GoodsSpec goodsSpec = goodsSpecService.getById(secKillActivitySpecBean.getGoodsSpecId());
                    if (secKillActivitySpecBean.getStockNum() > goodsSpec.getStockNum()) {
                        throw new RemoteServiceException(secKillActivitySpecBean.getGoodsName() + "库存超出");
                    }
                }
                String goodsId=null;
                if((goodsId=secKillActivitySpecBean.getGoodsId())==null){
                    throw new RemoteServiceException("无效商品");
                }
                Goods goods = goodsService.getById(goodsId);
                if(goods==null){
                    throw new RemoteServiceException("无效商品");
                }
                if(goods.getPromotionGroup()){
                    throw new RemoteServiceException("商品("+goods.getGoodsName()+")为团购商品无法进行秒杀");
                }
            }
        }
        Date creatDate = new Date();
        SecKillActivity secKillActivity = new SecKillActivity();
        BeanUtils.copyProperties(secKillActivityBean, secKillActivity);
        secKillActivity.setCreateTime(creatDate);
        secKillActivity.setStatus(true);
        secKillActivity.setCompanyWechatId(adminUser.getCompanyWechatId());
        secKillActivity.setCompanyName(adminUser.getCompanyName());
        secKillActivityService.save(secKillActivity);
        for (SecKillStage secKillStage : secKillActivityBean.getStages()) {
            secKillStage.setSecKillId(secKillActivity.getSecKillId());
            secKillStage.setCreateTime(creatDate);
            secKillStage.setCompanyWechatId(adminUser.getCompanyWechatId());
            secKillStage.setCompanyName(adminUser.getCompanyName());
            secKillStageService.save(secKillStage);
        }
        for (SecKillActivitySpec secKillActivitySpec : secKillActivityBean.getGoodsSpecs()) {
            secKillActivitySpec.setSecKillId(secKillActivity.getSecKillId());
            secKillActivitySpec.setCreateTime(creatDate);
            secKillActivitySpec.setStatus(true);
            secKillActivitySpec.setCompanyWechatId(adminUser.getCompanyWechatId());
            secKillActivitySpec.setCompanyName(adminUser.getCompanyName());
            secKillActivitySpec.setAmount(limitShareAmount(secKillActivitySpec.getPrice(), secKillActivitySpec.getSharePercent() != null
                    && secKillActivitySpec.getSharePercent().compareTo(new Double("0.00")) > 0 ?
                    secKillActivitySpec.getPrice().multiply(new BigDecimal(secKillActivitySpec.getSharePercent() / 100.0)).setScale(2, BigDecimal.ROUND_DOWN)
                    : secKillActivitySpec.getAmount()));
            secKillActivitySpecService.save(secKillActivitySpec);
            goodsSpecService.lambdaUpdate()
                    .eq(GoodsSpec::getGoodsSpecId, secKillActivitySpec.getGoodsSpecId())
                    .set(GoodsSpec::getFlag, true)
                    .update();
        }

    }

    private BigDecimal limitShareAmount(BigDecimal price, BigDecimal shareAmount) {
        BigDecimal shareLimit = price.multiply(new BigDecimal(percentLimit));
        return shareAmount.compareTo(shareLimit) < 1 ?
                shareAmount.setScale(2, BigDecimal.ROUND_DOWN)
                : shareLimit.setScale(2, BigDecimal.ROUND_DOWN);
    }


    /**
     * 修改秒杀商品
     *
     * @param secKillActivityBean
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(HttpServletRequest request, SecKillActivityBean secKillActivityBean) throws RemoteServiceException {
        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        String loginCompanyWechatId = adminUser.getCompanyWechatId();

        Integer count = secKillActivityService.lambdaQuery()
                .ne(SecKillActivity::getSecKillId, secKillActivityBean.getSecKillId())
                .eq(SecKillActivity::getStatus, true)
                .eq(SecKillActivity::getDel, false)
                .and(o1 -> o1.between(SecKillActivity::getStartTime, secKillActivityBean.getStartTime(), secKillActivityBean.getEndTime())
                        .or(o2 -> o2.between(SecKillActivity::getEndTime, secKillActivityBean.getStartTime(), secKillActivityBean.getEndTime()))
                        .or(o3 -> o3
                                .lt(SecKillActivity::getStartTime,secKillActivityBean.getStartTime())
                                .gt(SecKillActivity::getEndTime,secKillActivityBean.getEndTime()))
                )
                .eq(SecKillActivity::getCompanyWechatId, loginCompanyWechatId)
                .count();
        if (count > 0) {
            throw new RemoteServiceException("活动时间不能重叠");
        }
        secKillActivityBean.setCreateTime(null);
        secKillActivityService.updateById(secKillActivityBean);
        secKillActivitySpecService.lambdaUpdate()
                .eq(SecKillActivitySpec::getSecKillId, secKillActivityBean.getSecKillId())
                .remove();
        if (secKillActivityBean.getGoodsSpecs() != null) {

            for (SecKillActivitySpec secKillActivitySpec : secKillActivityBean.getGoodsSpecs()) {
                secKillActivitySpec.setCreateTime(new Date());
                secKillActivitySpec.setSecKillId(secKillActivityBean.getSecKillId());
                secKillActivitySpec.setAmount(limitShareAmount(secKillActivitySpec.getPrice(), secKillActivitySpec.getSharePercent() != null
                        && secKillActivitySpec.getSharePercent().compareTo(new Double("0.00")) > 0 ?
                        secKillActivitySpec.getPrice().multiply(new BigDecimal(secKillActivitySpec.getSharePercent() / 100.0)).setScale(2, BigDecimal.ROUND_DOWN)
                        : secKillActivitySpec.getAmount()));
                secKillActivitySpecService.save(secKillActivitySpec);
                goodsSpecService.lambdaUpdate()
                        .eq(GoodsSpec::getGoodsSpecId, secKillActivitySpec.getGoodsSpecId())
                        .set(GoodsSpec::getFlag, true)
                        .update();
            }
        }
        secKillStageService.lambdaUpdate()
                .eq(SecKillStage::getSecKillId, secKillActivityBean.getSecKillId())
                .remove();
        if (secKillActivityBean.getStages() != null) {
            for (SecKillStage secKillStage : secKillActivityBean.getStages()) {
                secKillStage.setCreateTime(new Date());
                secKillStage.setSecKillId(secKillActivityBean.getSecKillId());
                secKillStageService.save(secKillStage);
            }
        }
    }


    /**
     * 更改活动状态
     *
     * @param secKillId
     */
    public void updateStatus(String secKillId, Boolean status) {
        secKillActivityService.lambdaUpdate()
                .eq(SecKillActivity::getSecKillId, secKillId)
                .set(SecKillActivity::getStatus, status)
                .update();
    }

    /**
     * 删除秒杀商品
     *
     * @param secKillSpecId
     */
    public void specDelete(String secKillSpecId) {
        secKillActivitySpecService.removeById(secKillSpecId);
    }

    /**
     * 关闭秒杀商品
     *
     * @param secKillSpecId
     */
    public void specClose(String secKillSpecId) {
        secKillActivitySpecService.lambdaUpdate()
                .eq(SecKillActivitySpec::getSecKillSpecId, secKillSpecId)
                .set(SecKillActivitySpec::getStatus, true)
                .update();
    }


    public void updateStockNum(String secKillSpecId, Integer stockNum) {
        SecKillActivitySpec secKillActivitySpec = secKillActivitySpecService.getById(secKillSpecId);
        GoodsSpec goodsSpec = goodsSpecService.lambdaQuery().eq(GoodsSpec::getGoodsSpecId, secKillActivitySpec.getGoodsSpecId())
                .one();
        if ((secKillActivitySpec.getSecStockNum() + stockNum) > goodsSpec.getStockNum()) {
            return;
        }
        String key = secKillActivitySpec.getGoodsId() + "_" + secKillActivitySpec.getSecKillId() + "_" + secKillSpecId;
        Lock obtain = redisLockRegistry.obtain(LOCK_ORDER_STOCK + key);
        try {
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                log.error("修改秒杀库存获取锁失败");
            }
            //修改库存
            if (secKillActivitySpec != null && secKillActivitySpec.getSecStockNum() > 0) {
                secKillActivitySpecService.lambdaUpdate()
                        .eq(SecKillActivitySpec::getSecKillSpecId, secKillActivitySpec.getSecKillSpecId())
                        .set(SecKillActivitySpec::getSecStockNum, secKillActivitySpec.getSecStockNum() + stockNum)
                        .update();
            }

        } catch (Exception e) {
            log.info("修改秒杀库存secSpecId:" + secKillSpecId, e);
        } finally {
            obtain.unlock();
        }

    }


    /**
     * 秒杀商品详情
     *
     * @param secKillId
     * @return
     */
    public SecKillActivityBean detail(String secKillId) {
        SecKillActivity secKillActivity = secKillActivityService.lambdaQuery()
                .eq(SecKillActivity::getSecKillId, secKillId)
                .one();
        List<SecKillStage> secKillStages = secKillStageService.lambdaQuery()
                .eq(SecKillStage::getSecKillId, secKillId)
                .list();
        SecKillActivityBean secKillActivityBean = new SecKillActivityBean();
        secKillActivityBean.setStages(secKillStages);
        BeanUtils.copyProperties(secKillActivity, secKillActivityBean);
        secKillActivityBean.setGoodsSpecs(secKillMapper.querySecDetail(secKillId));
        return secKillActivityBean;
    }

    public IPage<CustomSpecBean> goodsSpecList(String categoryId, String keyword, Integer pageNum, Integer pageSize,HttpServletRequest request) {

        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        IPage<CustomSpecBean> page = secKillMapper.querySpecList(new Page(pageNum, pageSize), categoryId, keyword,adminUser.getCompanyWechatIds());
        return page;
    }


    public IPage<CustomSecSpecBeanVO> pageV2(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<String> companyWechatIds = adminUser.getCompanyWechatIds();

        //1.组装查询条件
        ZfireParamBean zfireParam = FieldUtils.supplyParam(zfireParamBean);
        List<QueryParamBean> collect = zfireParam.getParams().stream().filter(item -> item.getParam().equals("s.status")).collect(Collectors.toList());


        List<QueryParamBean> filter = zfireParam.getParams().stream().filter(item -> !item.getParam().equals("s.status")).collect(Collectors.toList());
        zfireParam.setParams(filter);
        IPage<CustomSecSpecBeanVO> customSecSpecBeanVOIPage = commonPageV2Mapper.pageV2Sec(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()),
                zfireParam
                , companyWechatIds
             , CollectionUtils.isEmpty(collect)?null:(Integer)collect.get(0).getValue());

        return customSecSpecBeanVOIPage;
    }

    public IPage<SecKillActivityStageBeanVO> pageV2Activity(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<String> companyWechatIds = adminUser.getCompanyWechatIds();

        //1.组装查询条件
        ZfireParamBean zfireParam = FieldUtils.supplyParam(zfireParamBean,SecKillActivityStageBeanVO.class);


        IPage<SecKillActivityStageBeanVO> secKillActivityStageBeanVOIPage = commonPageV2Mapper.pageV2Activity(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()),
                zfireParam
                , companyWechatIds
                );

        return secKillActivityStageBeanVOIPage;
    }
}
