package com.slodon.b2b2c.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.slodon.b2b2c.core.constant.PromotionConst;
import com.slodon.b2b2c.core.constant.RedisConst;
import com.slodon.b2b2c.core.constant.TplPcConst;
import com.slodon.b2b2c.core.util.FileUrlUtil;
import com.slodon.b2b2c.core.util.StringUtil;
import com.slodon.b2b2c.goods.example.GoodsPromotionExample;
import com.slodon.b2b2c.goods.pojo.Goods;
import com.slodon.b2b2c.goods.pojo.GoodsPromotion;
import com.slodon.b2b2c.model.goods.GoodsModel;
import com.slodon.b2b2c.model.goods.GoodsPromotionModel;
import com.slodon.b2b2c.model.promotion.PromotionCommonModel;
import com.slodon.b2b2c.model.system.BillModel;
import com.slodon.b2b2c.model.system.SettingModel;
import com.slodon.b2b2c.model.system.TplMobileDecoModel;
import com.slodon.b2b2c.model.system.TplPcMallDecoModel;
import com.slodon.b2b2c.system.example.TplMobileDecoExample;
import com.slodon.b2b2c.system.example.TplPcMallDecoExample;
import com.slodon.b2b2c.system.pojo.Setting;
import com.slodon.b2b2c.system.pojo.TplMobileDeco;
import com.slodon.b2b2c.system.pojo.TplPcMallDeco;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import static com.alibaba.fastjson.serializer.SerializerFeature.WriteMapNullValue;

@Slf4j
@Component
@Configuration      //1.主要用于标记配置类，兼备Component的效果。
//@EnableScheduling   //2.开启定时任务
public class SystemJob {

    //3.添加定时任务
//    @Scheduled(cron = "0 0/1 * * * ?")
//    @SchedulerLock(name = "configureTasks", lockAtMostFor = "60000", lockAtLeastFor = "50000")
//    public void configureTasks() {
//        log.info("shedlock锁测试========================: " + System.getProperty("server.port"));
//    }

    @Resource
    private BillModel billModel;
    @Resource
    private GoodsModel goodsModel;
    @Resource
    private TplMobileDecoModel tplMobileDecoModel;
    @Resource
    private TplPcMallDecoModel tplPcMallDecoModel;
    @Resource
    private GoodsPromotionModel goodsPromotionModel;
    @Resource
    private PromotionCommonModel promotionCommonModel;
    @Resource
    private RedisTemplate<String, Object> objectRedisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private SettingModel settingModel;

    /**
     * 商家结算账单生成定时任务
     * 查询所有商家，每个商家每个结算周期生成一条结算账单
     * 计算周期内商家所有的订单金额合计
     * 计算所有订单下订单货品明细的佣金
     * 计算周期内发生的退货退款（当前周期结算的订单如果在下个结算周期才退款，退款结算在下个周期计算）
     * 每个商家一个事务，某个商家结算时发生错误不影响其他结算
     * 每天0点半执行一次
     * <p>
     * 通过设置lockAtMostFor，我们可以确保即使节点死亡，锁也会被释放;通过设置lockAtLeastFor，
     * 我们可以确保它在23小时内不会执行超过一次。请注意，对于执行任务的节点死亡的情况，
     * lockAtMostFor只是一个安全网，所以将它设置为一个时间，这个时间远远大于最大估计执行时间。
     * 如果任务花费的时间比lockAtMostFor更长，那么它可能会再次执行，结果将是不可预测的(更多的进程将持有锁)。
     */
//    @Scheduled(cron = "0 30 0 * * ?")
//    @SchedulerLock(name = "billJobSchedule", lockAtMostFor = "86400000", lockAtLeastFor = "82800000")
    public void billJobSchedule() {
        log.info("billJobSchedule() start");
        try {
            billModel.billJobSchedule();
        } catch (Exception e) {
            log.error("billJobSchedule()", e);
        }
        log.info("billJobSchedule() end");
    }

    /**
     * 定时更新系统模块手机装修商品销量
     * 每隔十分钟执行一次
     */
//    @Scheduled(cron = "10 0/10 * * * ?")
//    @SchedulerLock(name = "jobUpdateSalesVolume", lockAtMostFor = "600000", lockAtLeastFor = "540000")
    public void jobUpdateSalesVolume() {
        log.info("jobUpdateSalesVolume() start");
        try {
            Map<Object, Object> map = objectRedisTemplate.opsForHash().entries(RedisConst.MOBILE_INDEX);
            if (map.size() > 0) {
                for (Map.Entry<Object, Object> entry : map.entrySet()) {
                    String os = (String) entry.getKey();
                    //序列化为Json字符串
                    String jsonString = JSON.toJSONString(entry.getValue());
                    //将Json字符串反序列化为Java对象
                    TplMobileDeco deco = JSON.parseObject(jsonString, TplMobileDeco.class);
                    String data = deco.getData();
                    if (!StringUtil.isEmpty(data)) {
                        Object parse = JSON.parse(data);
                        this.dealGoodsSale(parse);
                        data = JSON.toJSONString(parse, WriteMapNullValue);
                    }
                    ModelMap modelMap = new ModelMap();
                    modelMap.put("data", data);
                    modelMap.put("showTip", deco.getShowTip());
                    objectRedisTemplate.opsForHash().put(RedisConst.MOBILE_INDEX, os, modelMap);
                }
            } else {
                TplMobileDecoExample example = new TplMobileDecoExample();
                example.setStoreId(0L);
                example.setQueryData("notNull");
                List<TplMobileDeco> list = tplMobileDecoModel.getTplMobileDecoList(example, null);
                if (!CollectionUtils.isEmpty(list)) {
                    for (TplMobileDeco deco : list) {
                        if (StringUtil.isEmpty(deco.getData())) {
                            continue;
                        }
                        String data = deco.getData();
                        if (!StringUtil.isEmpty(data)) {
                            Object parse = JSON.parse(data);
                            this.dealGoodsSale(parse);
                            data = JSON.toJSONString(parse, WriteMapNullValue);
                        }

                        //装修页类型为首页，存入redis
                        if (deco.getType().equals("home")) {
                            ModelMap modelMap = new ModelMap();
                            modelMap.put("data", data);
                            modelMap.put("showTip", deco.getShowTip());
                            //设备标识：android，ios，h5，weixinXcx，alipayXcx
                            if (deco.getAndroid() == TplPcConst.IS_ENABLE_YES) {
                                objectRedisTemplate.opsForHash().put(RedisConst.MOBILE_INDEX, "android", modelMap);
                            }
                            if (deco.getIos() == TplPcConst.IS_ENABLE_YES) {
                                objectRedisTemplate.opsForHash().put(RedisConst.MOBILE_INDEX, "ios", modelMap);
                            }
                            if (deco.getH5() == TplPcConst.IS_ENABLE_YES) {
                                objectRedisTemplate.opsForHash().put(RedisConst.MOBILE_INDEX, "h5", modelMap);
                            }
                            if (deco.getWeixinXcx() == TplPcConst.IS_ENABLE_YES) {
                                objectRedisTemplate.opsForHash().put(RedisConst.MOBILE_INDEX, "weixinXcx", modelMap);
                            }
                        }
                    }
                }
            }
            //同时更新一下推手首页装修数据
            this.updateSpreadTplData();
        } catch (Exception e) {
            log.error("jobUpdateSalesVolume()", e);
        }
        log.info("jobUpdateSalesVolume() end");
    }

    /**
     * 更新推手首页装修数据
     */
    public void updateSpreadTplData() {
        TplMobileDecoExample example = new TplMobileDecoExample();
        example.setStoreId(0L);
        example.setType("spreader");
        example.setQueryData2("notNull");
        List<TplMobileDeco> list = tplMobileDecoModel.getTplMobileDecoList(example, null);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (TplMobileDeco deco : list) {
            if (StringUtil.isEmpty(deco.getData())) {
                continue;
            }
            String data = deco.getData();
            if (!StringUtil.isEmpty(data)) {
                Object parse = JSON.parse(data);
                this.dealGoodsSale(parse);
                data = JSON.toJSONString(parse, WriteMapNullValue);
            }
            TplMobileDeco tplMobileDeco = new TplMobileDeco();
            tplMobileDeco.setDecoId(deco.getDecoId());
            tplMobileDeco.setData(data);
            tplMobileDecoModel.updateTplMobileDeco(tplMobileDeco);
        }
    }

    /**
     * 定时更新系统模块PC装修商品销量
     * 每隔十分钟执行一次
     */
    @Scheduled(cron = "20 0/10 * * * ?")
    @SchedulerLock(name = "jobUpdatePcSalesVolume", lockAtMostFor = "600000", lockAtLeastFor = "540000")
    public void jobUpdatePcSalesVolume() {
        List<Setting> settingList = settingModel.getSiteSetting();
        if (!CollectionUtils.isEmpty(settingList)) {
            settingList.forEach(setting -> {
                log.info("jobUpdatePcSalesVolume() start");
                try {
                    String data;
                    String pcIndex = stringRedisTemplate.opsForValue().get(RedisConst.PC_INDEX + "_" + setting.getValue());
                    if (!StringUtils.isEmpty(pcIndex)) {
                        Object parse = JSON.parse(pcIndex);
                        this.dealGoodsSale(parse);
                        data = JSON.toJSONString(parse, WriteMapNullValue);
                    } else {
                        TplPcMallDeco deco = null;
                        TplPcMallDecoExample example = new TplPcMallDecoExample();
                        example.setWebSite(setting.getValue());
                        example.setIsEnable(TplPcConst.IS_ENABLE_YES);
                        example.setDecoType("index");
                        example.setStoreId(0L);
                        List<TplPcMallDeco> list = tplPcMallDecoModel.getTplPcMallDecoList(example, null);
                        if (!CollectionUtils.isEmpty(list)) {
                            deco = list.get(0);
                        }
                        if (deco == null) {
                            return;
                        }
                        data = deco.getData();
                    }
                    //存入redis
                    stringRedisTemplate.opsForValue().set(RedisConst.PC_INDEX + "_" + setting.getValue(), data);
                } catch (Exception e) {
                    log.error("jobUpdatePcSalesVolume()", e);
                }
                log.info("jobUpdatePcSalesVolume() end");
            });
        }
    }

    /**
     * 替换json对象中的商品销量
     *
     * @param object json对象
     */
    private void dealGoodsSale(Object object) {
        if (object instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) object;
            if (jsonObject.containsKey("goodsId")) {
                Long goodsId = jsonObject.getLong("goodsId");
                //查询商品信息
                Goods goods = goodsModel.getGoodsByGoodsId(goodsId);
                // 如果商品不存在或不是上架状态，则从JSON中移除该商品
                if (goods == null || goods.getState() == null || goods.getState() != 3) {
                    // 标记需要移除的商品，但不在遍历过程中直接移除
                    return;
                }
                    if (jsonObject.containsKey("actualSales")) {
                        //销量
                        int salesVolume = goods.getActualSales() + goods.getVirtualSales();
                        jsonObject.put("actualSales", salesVolume);
                    }
                    if (jsonObject.containsKey("goodsPrice")) {
                        //价格
                        jsonObject.put("goodsPrice", this.getPromotionPrice(goods));
                    }
                    if (jsonObject.containsKey("mainImage")) {
                        //图片
                        jsonObject.put("mainImage", FileUrlUtil.getFileUrl(goods.getMainImage(), null));
                    }
                    if (jsonObject.containsKey("goodsName")) {
                        //名称
                        jsonObject.put("goodsName", goods.getGoodsName());
                    }

            }
            jsonObject.values().forEach(this::dealGoodsSale);
            return;
        }
        if (object instanceof JSONArray) {
            JSONArray o = (JSONArray) object;
            // 使用迭代器以便在遍历过程中安全地移除元素
            o.removeIf(item -> {
                if (item instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) item;
                    if (jsonObject.containsKey("goodsId")) {
                        Long goodsId = jsonObject.getLong("goodsId");
                        Goods goods = goodsModel.getGoodsByGoodsId(goodsId);
                        // 如果商品不存在或不是上架状态，则移除该商品
                        return goods == null || goods.getState() == null || goods.getState() != 3;
                    }
                }
                // 对于数组中的其他元素，递归处理
                dealGoodsSale(item);
                return false;
            });
        }
    }

    /**
     * 获取活动价
     *
     * @param goods 商品信息
     * @return
     */
    public BigDecimal getPromotionPrice(Goods goods) {
        //商品参与的活动
        GoodsPromotionExample example = new GoodsPromotionExample();
        example.setGoodsId(goods.getGoodsId());
        example.setProductId(goods.getDefaultProductId());
        example.setIsEffective(PromotionConst.IS_EFFECTIVE_YES);
        example.setBindType(PromotionConst.BIND_TYPE_1);
        List<GoodsPromotion> list = goodsPromotionModel.getGoodsPromotionList(example, null);
        if (CollectionUtils.isEmpty(list)) {
            return goods.getGoodsPrice();
        }
        GoodsPromotion goodsPromotion = list.get(0);
        BigDecimal promotionPrice = promotionCommonModel.getPromotionPrice(goodsPromotion.getPromotionType(), goodsPromotion.getPromotionId(), goodsPromotion.getProductId());
        if (promotionPrice.compareTo(BigDecimal.ZERO) > 0) {
            return promotionPrice;
        } else {
            return goods.getGoodsPrice();
        }
    }
}
