package com.liquidnet.client.admin.zhengzai.goblin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.client.admin.zhengzai.goblin.service.IGoblinArtistTopicAdminService;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.service.goblin.constant.GoblinArtistConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinArtistTopicVo;
import com.liquidnet.service.goblin.entity.GoblinArtistTopic;
import com.liquidnet.service.goblin.entity.GoblinArtistTopicGoods;
import com.liquidnet.service.goblin.entity.GoblinGoods;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import com.liquidnet.service.goblin.mapper.GoblinArtistTopicGoodsMapper;
import com.liquidnet.service.goblin.mapper.GoblinArtistTopicMapper;
import com.liquidnet.service.goblin.mapper.GoblinGoodsMapper;
import com.liquidnet.service.goblin.mapper.GoblinGoodsSkuMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GoblinArtistTopicAdminServiceImpl
        extends ServiceImpl<GoblinArtistTopicMapper, GoblinArtistTopic>
        implements IGoblinArtistTopicAdminService {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisDataSourceUtil redisDataSourceUtil;
    @Autowired
    private GoblinArtistTopicGoodsMapper topicGoodsMapper;
    @Autowired
    private GoblinGoodsMapper goodsMapper;
    @Autowired
    private GoblinGoodsSkuMapper goodsSkuMapper;

    @Override
    @Transactional
    public boolean setSort(String topicId, int sort) {
        LocalDateTime now = LocalDateTime.now();
        this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .set(GoblinArtistTopic::getSort, sort)
                .set(GoblinArtistTopic::getUpdatedAt, now));

        mongoTemplate.updateFirst(Query.query(Criteria.where("topicId").is(topicId)),
                Update.update("sort", sort).set("updatedAt", now),
                GoblinArtistTopicVo.class.getSimpleName());

        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.ARTIST_TOPIC + topicId);
        return true;
    }

    @Override
    @Transactional
    public boolean setRecommend(String topicId, int position) {
        if (position != 0 && (position < GoblinArtistConst.RECOMMEND_MIN
                || position > GoblinArtistConst.RECOMMEND_MAX)) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();

        if (position > 0) {
            mongoTemplate.updateMulti(
                    Query.query(Criteria.where("recommendPosition").is(position)),
                    Update.update("recommendPosition", 0),
                    GoblinArtistTopicVo.class.getSimpleName());
            this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                    .eq(GoblinArtistTopic::getRecommendPosition, position)
                    .set(GoblinArtistTopic::getRecommendPosition, 0)
                    .set(GoblinArtistTopic::getUpdatedAt, now));
        }

        this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .set(GoblinArtistTopic::getRecommendPosition, position)
                .set(GoblinArtistTopic::getUpdatedAt, now));

        mongoTemplate.updateFirst(Query.query(Criteria.where("topicId").is(topicId)),
                Update.update("recommendPosition", position).set("updatedAt", now),
                GoblinArtistTopicVo.class.getSimpleName());

        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.ARTIST_TOPIC + topicId);
        return true;
    }

    @Override
    @Transactional
    public boolean setTag(String topicId, String tag) {
        LocalDateTime now = LocalDateTime.now();
        String normalized = StringUtils.isBlank(tag) ? null : tag.trim();
        if (normalized != null
                && !GoblinArtistConst.TAG_NEW.equals(normalized)
                && !GoblinArtistConst.TAG_HOT.equals(normalized)) {
            return false;
        }

        this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .set(GoblinArtistTopic::getTag, normalized)
                .set(GoblinArtistTopic::getUpdatedAt, now));

        mongoTemplate.updateFirst(Query.query(Criteria.where("topicId").is(topicId)),
                Update.update("tag", normalized).set("updatedAt", now),
                GoblinArtistTopicVo.class.getSimpleName());

        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.ARTIST_TOPIC + topicId);
        return true;
    }

    @Override
    @Transactional
    public boolean setStatus(String topicId, int status) {
        LocalDateTime now = LocalDateTime.now();
        this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .set(GoblinArtistTopic::getStatus, status)
                .set(GoblinArtistTopic::getUpdatedAt, now));

        mongoTemplate.updateFirst(Query.query(Criteria.where("topicId").is(topicId)),
                Update.update("status", status).set("updatedAt", now),
                GoblinArtistTopicVo.class.getSimpleName());

        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.ARTIST_TOPIC + topicId);
        return true;
    }

    @Override
    @Transactional
    public boolean deleteTopic(String topicId) {
        LocalDateTime now = LocalDateTime.now();
        this.update(new LambdaUpdateWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .set(GoblinArtistTopic::getDelFlg, GoblinArtistConst.DEL_YES)
                .set(GoblinArtistTopic::getUpdatedAt, now));

        mongoTemplate.updateFirst(Query.query(Criteria.where("topicId").is(topicId)),
                Update.update("delFlg", GoblinArtistConst.DEL_YES).set("updatedAt", now),
                GoblinArtistTopicVo.class.getSimpleName());

        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.ARTIST_TOPIC + topicId);
        return true;
    }

    @Override
    public Map<String, Object> topicDetail(String topicId) {
        GoblinArtistTopic topic = this.getOne(new LambdaQueryWrapper<GoblinArtistTopic>()
                .eq(GoblinArtistTopic::getTopicId, topicId)
                .eq(GoblinArtistTopic::getDelFlg, GoblinArtistConst.DEL_NO));
        if (topic == null) {
            return null;
        }
        List<GoblinArtistTopicGoods> relations = topicGoodsMapper.selectList(
                new LambdaQueryWrapper<GoblinArtistTopicGoods>()
                        .eq(GoblinArtistTopicGoods::getTopicId, topicId)
                        .orderByAsc(GoblinArtistTopicGoods::getSort));

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("topicId", topic.getTopicId());
        result.put("storeId", topic.getStoreId());
        result.put("topicName", topic.getTopicName());
        result.put("artistId", topic.getArtistId());
        result.put("templateType", topic.getTemplateType());
        result.put("bannerUrl", topic.getBannerUrl());
        result.put("bannerHeight", topic.getBannerHeight());
        result.put("onSaleStart", topic.getOnSaleStart());
        result.put("onSaleEnd", topic.getOnSaleEnd());
        result.put("status", topic.getStatus());
        result.put("sort", topic.getSort());
        result.put("recommendPosition", topic.getRecommendPosition());
        result.put("tag", topic.getTag());
        result.put("createdAt", topic.getCreatedAt());
        result.put("updatedAt", topic.getUpdatedAt());
        result.put("goods", buildGoods(relations));
        return result;
    }

    /**
     * 按关联表拼商品明细：名称/封面/价格取商品表，规格取 SKU 表（一个商品可能有多个规格，顿号分隔）
     */
    private List<Map<String, Object>> buildGoods(List<GoblinArtistTopicGoods> relations) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (relations.isEmpty()) {
            return list;
        }
        Set<String> spuIds = relations.stream()
                .map(GoblinArtistTopicGoods::getSpuId)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());

        Map<String, GoblinGoods> goodsMap = goodsMapper.selectList(
                        new LambdaQueryWrapper<GoblinGoods>().in(GoblinGoods::getSpuId, spuIds))
                .stream().collect(Collectors.toMap(GoblinGoods::getSpuId, g -> g, (a, b) -> a));

        List<GoblinGoodsSku> skus = goodsSkuMapper.selectList(
                new LambdaQueryWrapper<GoblinGoodsSku>()
                        .in(GoblinGoodsSku::getSpuId, spuIds)
                        .eq(GoblinGoodsSku::getDelFlg, "0"));
        Map<String, String> specMap = skus.stream()
                .filter(sku -> StringUtils.isNotBlank(sku.getName()))
                .collect(Collectors.groupingBy(GoblinGoodsSku::getSpuId,
                        Collectors.mapping(GoblinGoodsSku::getName, Collectors.joining("、"))));

        for (GoblinArtistTopicGoods relation : relations) {
            GoblinGoods goods = goodsMap.get(relation.getSpuId());
            Map<String, Object> good = new LinkedHashMap<>();
            good.put("spuId", relation.getSpuId());
            good.put("sort", relation.getSort());
            good.put("name", goods == null ? null : goods.getName());
            good.put("coverPic", goods == null ? null : goods.getCoverPic());
            good.put("sellPrice", formatGoodsPrice(goods, skus, relation.getSpuId()));
            good.put("spec", specMap.get(relation.getSpuId()));
            list.add(good);
        }
        return list;
    }

    /**
     * 计算并格式化商品价格：优先用 priceGe 和 priceLe。若相同取一个，若不同展示区间。
     */
    private String formatGoodsPrice(GoblinGoods goods, List<GoblinGoodsSku> skus, String spuId) {
        BigDecimal ge = goods != null ? goods.getPriceGe() : null;
        BigDecimal le = goods != null ? goods.getPriceLe() : null;

        if (ge != null && le != null) {
            if (ge.compareTo(le) == 0) {
                return ge.setScale(2, java.math.RoundingMode.HALF_UP).toString();
            } else {
                return ge.setScale(2, java.math.RoundingMode.HALF_UP).toString() + " ~ " + le.setScale(2, java.math.RoundingMode.HALF_UP).toString();
            }
        }
        if (ge != null) {
            return ge.setScale(2, java.math.RoundingMode.HALF_UP).toString();
        }
        if (le != null) {
            return le.setScale(2, java.math.RoundingMode.HALF_UP).toString();
        }
        if (goods != null && goods.getSellPrice() != null) {
            return goods.getSellPrice().setScale(2, java.math.RoundingMode.HALF_UP).toString();
        }

        // 兜底查 SKU 价格
        List<BigDecimal> skuPrices = skus.stream()
                .filter(s -> StringUtils.equals(s.getSpuId(), spuId))
                .map(s -> s.getPrice() != null ? s.getPrice() : s.getSellPrice())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (!skuPrices.isEmpty()) {
            BigDecimal min = Collections.min(skuPrices);
            BigDecimal max = Collections.max(skuPrices);
            if (min.compareTo(max) == 0) {
                return min.setScale(2, java.math.RoundingMode.HALF_UP).toString();
            } else {
                return min.setScale(2, java.math.RoundingMode.HALF_UP).toString() + " ~ " + max.setScale(2, java.math.RoundingMode.HALF_UP).toString();
            }
        }

        return null;
    }

    @Override
    public Map<String, Integer> goodsCountMap(Collection<String> topicIds) {
        if (CollectionUtils.isEmpty(topicIds)) {
            return Collections.emptyMap();
        }
        List<GoblinArtistTopicGoods> relations = topicGoodsMapper.selectList(
                new LambdaQueryWrapper<GoblinArtistTopicGoods>()
                        .in(GoblinArtistTopicGoods::getTopicId, topicIds));
        return relations.stream().collect(Collectors.groupingBy(
                GoblinArtistTopicGoods::getTopicId, Collectors.summingInt(r -> 1)));
    }
}
