package com.liquidnet.service.kylin.service.impl.admin;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.BeanUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dao.BannerDetailsListDao;
import com.liquidnet.service.kylin.dto.param.BannersParam;
import com.liquidnet.service.kylin.dto.param.BannersSearchParam;
import com.liquidnet.service.kylin.dto.vo.BannersVo;
import com.liquidnet.service.kylin.entity.KylinBanners;
import com.liquidnet.service.kylin.entity.KylinBannersRelations;
import com.liquidnet.service.kylin.mapper.KylinBannersMapper;
import com.liquidnet.service.kylin.mapper.KylinBannersRelationsMapper;
import com.liquidnet.service.kylin.service.admin.IKylinBannersService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import com.mysql.cj.util.StringUtils;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 轮播图 服务实现类
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-05-02
 */
@Service
public class KylinBannersServiceImpl extends ServiceImpl<KylinBannersMapper, KylinBanners> implements IKylinBannersService {

    @Autowired
    private KylinBannersMapper bannersMapper;

    @Autowired
    private KylinBannersRelationsMapper kylinBannersRelationsMapper;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private MongoConverter mongoConverter;

    @Autowired
    RedisUtil redisUtil;

    public boolean create(BannersParam bannersParam) {
        try {
            // 时间
            String bannersId = IDGenerator.nextSnowId().toString();
            LocalDateTime createdAt = LocalDateTime.now();
            String createdAtString = createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            // 入数据库
            bannersMapper.insert(bannersParam.getFields(bannersId, createdAtString));

            List<String> positionList = bannersParam.getPositionList();
            KylinBannersRelations kylinBannersRelations = new KylinBannersRelations();
            for (String fieldId : positionList) {
                KylinBannersRelations relations = kylinBannersRelations.newData(bannersId, fieldId, 1, createdAtString);
                kylinBannersRelationsMapper.insert(relations);
            }
            List<String> provincesList = bannersParam.getProvincesList();
            if (!provincesList.isEmpty()) {
                for (String fieldId : provincesList) {
                    KylinBannersRelations relations = kylinBannersRelations.newData(bannersId, fieldId, 2, createdAtString);
                    kylinBannersRelationsMapper.insert(relations);
                }
            } else {
                provincesList = new ArrayList();
            }

            // 处理缓存数据
            BannersVo bannersVo = new BannersVo();
            BeanUtils.copyProperties(bannersParam, bannersVo);
            bannersVo.setBannersId(bannersId);
            bannersVo.setCreatedAt(createdAtString);
            // 处理基础数据 防止缓存中无字段
            bannersVo.setIsDeleted(1);
            bannersVo.setUpdatedAt("");
            bannersVo.setPositionList(positionList);
            bannersVo.setProvincesList(provincesList);
            if (StringUtils.isNullOrEmpty(bannersParam.getTargetObj())) {
                bannersVo.setTargetObj("");
            }
            if (StringUtils.isNullOrEmpty(bannersParam.getOnlineStartTime())) {
                bannersVo.setOnlineEndTime("");
            }
            if (StringUtils.isNullOrEmpty(bannersParam.getOnlineEndTime())) {
                bannersVo.setOnlineEndTime("");
            }
            if (null == bannersParam.getBannersSort()) {
                bannersVo.setBannersSort(0);
            }
            if (StringUtils.isNullOrEmpty(bannersParam.getRemarks())) {
                bannersVo.setRemarks("");
            }
            // 入缓存
            mongoTemplate.insert(bannersVo, BannersVo.class.getSimpleName());

            redisUtil.hset(KylinRedisConst.BANNERS, bannersId, bannersVo);

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public boolean update(BannersParam bannersParam) {
        try {
            // 时间
            String bannersId = bannersParam.getBannersId();
            LocalDateTime updatedAt = LocalDateTime.now();
            String updatedAtString = updatedAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            KylinBanners params = bannersParam.getFields(null, null);
            params.setUpdatedAt(updatedAtString);
            // 入数据库
            bannersMapper.update(params, new UpdateWrapper<KylinBanners>().eq("banners_id", bannersId));

            List<String> positionList = bannersParam.getPositionList();
            KylinBannersRelations kylinBannersRelations = new KylinBannersRelations();
            // 入数据库 先删除之前的
            kylinBannersRelationsMapper.delete(
                    new UpdateWrapper<KylinBannersRelations>().eq("banners_id", bannersId).eq("field_id_type", 1)
            );
            for (String fieldId : positionList) {
                KylinBannersRelations relations = kylinBannersRelations.newData(bannersId, fieldId, 1, updatedAtString);
                kylinBannersRelationsMapper.insert(relations);
            }
            List<String> provincesList = bannersParam.getProvincesList();
            if (!provincesList.isEmpty()) {
                // 入数据库 先删除之前的
                kylinBannersRelationsMapper.delete(
                        new UpdateWrapper<KylinBannersRelations>().eq("banners_id", bannersId).eq("field_id_type", 2)
                );
                for (String fieldId : provincesList) {
                    KylinBannersRelations relations = kylinBannersRelations.newData(bannersId, fieldId, 2, updatedAtString);
                    kylinBannersRelationsMapper.insert(relations);
                }
            } else {
                provincesList = new ArrayList();
            }
            // 处理缓存数据
            BannersVo bannersVo = new BannersVo();
            BeanUtils.copyProperties(bannersParam, bannersVo);
            bannersVo.setBannersId(bannersId);
            bannersVo.setUpdatedAt(updatedAtString);
            bannersVo.setPositionList(positionList);
            bannersVo.setProvincesList(provincesList);
            // 修改缓存
            BasicDBObject object = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(bannersVo)));
            Document doc = mongoTemplate.getCollection(BannersVo.class.getSimpleName()).findOneAndUpdate(
                    Query.query(Criteria.where("bannersId").is(bannersId)).getQueryObject(),
                    object,
                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
            );

            redisUtil.hset(KylinRedisConst.BANNERS, bannersId, JsonUtils.fromJson(doc.toJson(), BannersVo.class));

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public KylinBanners detail(String bannersId) {
        KylinBanners data = bannersMapper.selectOne(new UpdateWrapper<KylinBanners>().eq("banners_id", bannersId).eq("is_deleted", 1));
        List<String> positionList = kylinBannersRelationsMapper.getBannersRelationsField("field_id", bannersId, 1);
        List<String> provincesList = kylinBannersRelationsMapper.getBannersRelationsField("field_id", bannersId, 2);

        data.setPositionList(positionList);
        data.setProvincesList(provincesList);

        return data;
    }

    public List<BannerDetailsListDao> bannerList(BannersSearchParam bannersSearchParam) {
        try {
            bannersSearchParam.setPage((bannersSearchParam.getPage() - 1) * bannersSearchParam.getSize());

            List<BannerDetailsListDao> data = bannersMapper.searchBannersList(BeanUtil.convertBeanToMap(bannersSearchParam));
            return data;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return new ArrayList<>();
        }
    }

    public Long bannerListCount(BannersSearchParam bannersSearchParam) {
        try {
            Long count = bannersMapper.searchBannersCount(BeanUtil.convertBeanToMap(bannersSearchParam));
            return count;
        } catch (Exception e) {
            return 0L;
        }
    }

    public Boolean delete(String bannersId) {
        try {
            LocalDateTime updatedAt = LocalDateTime.now();
            String updatedAtString = updatedAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            KylinBanners kylinBanners = new KylinBanners();
            kylinBanners.setUpdatedAt(updatedAtString);
            kylinBanners.setIsDeleted(0);
            bannersMapper.update(kylinBanners
                    , new UpdateWrapper<KylinBanners>().eq("banners_id", bannersId));

            // mongo 操作
            HashMap<String, Object> map = new HashMap<>();
            map.put("updatedAt", updatedAtString);
            map.put("isDeleted", 0);

            BasicDBObject object = new BasicDBObject("$set", mongoConverter.convertToMongoType(map));
            Document doc = mongoTemplate.getCollection(BannersVo.class.getSimpleName()).findOneAndUpdate(
                    Query.query(Criteria.where("bannersId").is(bannersId)).getQueryObject(),
                    object,
                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
            );

            // redis 操作
            redisUtil.hset(KylinRedisConst.BANNERS, bannersId, JsonUtils.fromJson(doc.toJson(), BannersVo.class));

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public List blist(String position, String provinceCode) {
        Query query = new Query();
        query.addCriteria(
                Criteria.where("isOnline").is(1).and("isDeleted").is(1)
        );

        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = nowTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Criteria onlineTimeBetween = Criteria.where("onlineStartTime").lte(nowTimeStr).and("onlineEndTime").gte(nowTimeStr);
        Criteria onlineTimeGt = Criteria.where("onlineStartTime").lte(nowTimeStr).and("onlineEndTime").is("");
        Criteria onlineTimeLt = Criteria.where("onlineStartTime").is("").and("onlineEndTime").gte(nowTimeStr);
        Criteria onlineTimeEmpty = Criteria.where("onlineStartTime").is("").and("onlineEndTime").is("");
        Criteria mergeCriteriaTime = new Criteria();
        mergeCriteriaTime.orOperator(onlineTimeBetween, onlineTimeGt, onlineTimeLt, onlineTimeEmpty);

        if (!position.isEmpty()) {
            query.addCriteria(
                    Criteria.where("positionList").in(position)
            );
        }

        Criteria mergeCriteriaPromotion = new Criteria();
        if (!provinceCode.isEmpty()) {
            Criteria promotionCity = Criteria.where("provincesList").in(provinceCode);
            Criteria promotionAll = Criteria.where("promotionType").is(1);
            mergeCriteriaPromotion.orOperator(promotionCity, promotionAll);
        }

        Criteria criteria = new Criteria();
        query.addCriteria(
                criteria.andOperator(mergeCriteriaTime, mergeCriteriaPromotion)
        );

        List bannerList = mongoTemplate.find(
                query,
                BannersVo.class,
                BannersVo.class.getSimpleName()
        );

        return bannerList;
    }

}
