package com.liquidnet.service.goblin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.constant.GoblinArtistConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinArtistAuthApplyVo;
import com.liquidnet.service.goblin.dto.vo.GoblinArtistTopicVo;
import com.liquidnet.service.goblin.dto.vo.GoblinFrontArtistTopicDetailVo;
import com.liquidnet.service.goblin.dto.vo.GoblinFrontArtistTopicHomeVo;
import com.liquidnet.service.goblin.dto.vo.GoblinFrontArtistTopicListPageVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.kylin.entity.KylinArtist;
import com.liquidnet.service.kylin.mapper.KylinArtistMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
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.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * C 端艺人专题（读路径：Redis → MongoDB）
 */
@Service
@Slf4j
public class GoblinFrontArtistTopicServiceImpl {

    private static final long TOPIC_TTL = 86400L;
    private static final String SORT_PRICE = "price";
    private static final String ORDER_DESC = "desc";

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private KylinArtistMapper kylinArtistMapper;

    // ======================== 首页入口 ========================

    public ResponseDto<GoblinFrontArtistTopicHomeVo> home() {
        List<GoblinArtistTopicVo> visible = visibleTopics();

        List<GoblinArtistTopicVo> recommended = visible.stream()
                .filter(t -> t.getRecommendPosition() != null
                        && t.getRecommendPosition() >= GoblinArtistConst.RECOMMEND_MIN
                        && t.getRecommendPosition() <= GoblinArtistConst.RECOMMEND_MAX)
                .sorted(Comparator.comparing(GoblinArtistTopicVo::getRecommendPosition))
                .collect(Collectors.toList());

        GoblinFrontArtistTopicHomeVo vo = new GoblinFrontArtistTopicHomeVo();
        vo.setTotal(visible.size());
        vo.setTopics(buildHomeItems(recommended));
        return ResponseDto.success(vo);
    }

    // ======================== 专题列表 ========================

    public ResponseDto<GoblinFrontArtistTopicListPageVo> list(int page, int size) {
        List<GoblinArtistTopicVo> visible = visibleTopics();

        int from = Math.min((page - 1) * size, visible.size());
        int to = Math.min(from + size, visible.size());

        GoblinFrontArtistTopicListPageVo vo = new GoblinFrontArtistTopicListPageVo();
        vo.setPage(page);
        vo.setSize(size);
        vo.setTotal(visible.size());
        vo.setList(buildListItems(visible.subList(from, to)));
        return ResponseDto.success(vo);
    }

    // ======================== 专题详情 ========================

    public ResponseDto<GoblinFrontArtistTopicDetailVo> detail(String topicId, String sortType, String sortOrder) {
        GoblinArtistTopicVo topic = loadTopic(topicId);
        if (topic == null || !isVisible(topic)) {
            return ResponseDto.failure("专题不存在");
        }

        GoblinFrontArtistTopicDetailVo vo = new GoblinFrontArtistTopicDetailVo();
        vo.setTopicId(topic.getTopicId());
        vo.setTopicName(topic.getTopicName());
        vo.setTag(topic.getTag());
        vo.setArtistId(topic.getArtistId());
        vo.setTemplateType(topic.getTemplateType());
        vo.setBannerUrl(topic.getBannerUrl());
        vo.setBannerHeight(topic.getBannerHeight());
        vo.setOnSaleStart(topic.getOnSaleStart());
        vo.setOnSaleEnd(topic.getOnSaleEnd());
        if (StringUtils.isNotBlank(topic.getArtistId())) {
            KylinArtist artist = kylinArtistMapper.selectOne(new LambdaQueryWrapper<KylinArtist>()
                    .eq(KylinArtist::getArtistId, topic.getArtistId())
                    .last("limit 1"));
            if (artist != null) {
                vo.setArtistName(artist.getArtistName());
                vo.setAvatarUrl(artist.getAvatarUrl());
            }
        }
        vo.setGoods(buildGoods(topic.getGoods(), sortType, sortOrder));
        return ResponseDto.success(vo);
    }

    // ======================== 私有：可见专题 ========================

    /** 已上架 + 未删除 + 上架区间内 + 艺人授权有效；sort ASC, createdAt DESC */
    private List<GoblinArtistTopicVo> visibleTopics() {
        LocalDateTime now = LocalDateTime.now();
        Query query = new Query(Criteria.where("status").is(GoblinArtistConst.TOPIC_ONLINE)
                .and("delFlg").is(GoblinArtistConst.DEL_NO)
                .andOperator(saleWindowCriteria(now)));
        query.with(Sort.by(Sort.Order.asc("sort"), Sort.Order.desc("createdAt")));
        List<GoblinArtistTopicVo> topics = mongoTemplate.find(query,
                GoblinArtistTopicVo.class, GoblinArtistTopicVo.class.getSimpleName());

        Set<String> authSet = validAuthSet(topics, now);
        return topics.stream()
                .filter(t -> StringUtils.isBlank(t.getArtistId())
                        || authSet.contains(t.getStoreId() + "_" + t.getArtistId()))
                .collect(Collectors.toList());
    }

    private boolean isVisible(GoblinArtistTopicVo topic) {
        if (!Objects.equals(topic.getStatus(), GoblinArtistConst.TOPIC_ONLINE)
                || !Objects.equals(topic.getDelFlg(), GoblinArtistConst.DEL_NO)) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();
        if (!withinSaleWindow(topic, now)) {
            return false;
        }
        return StringUtils.isBlank(topic.getArtistId())
                || !validAuthSet(Collections.singletonList(topic), now).isEmpty();
    }

    /** 上架区间：开始为空或已到，结束为空或未过 */
    private Criteria saleWindowCriteria(LocalDateTime now) {
        return new Criteria().andOperator(
                new Criteria().orOperator(
                        Criteria.where("onSaleStart").is(null),
                        Criteria.where("onSaleStart").lte(now)),
                new Criteria().orOperator(
                        Criteria.where("onSaleEnd").is(null),
                        Criteria.where("onSaleEnd").gte(now)));
    }

    private boolean withinSaleWindow(GoblinArtistTopicVo topic, LocalDateTime now) {
        return (topic.getOnSaleStart() == null || !topic.getOnSaleStart().isAfter(now))
                && (topic.getOnSaleEnd() == null || !topic.getOnSaleEnd().isBefore(now));
    }

    /** 有效授权（申请已通过且未过期）的 storeId_artistId 集合 */
    private Set<String> validAuthSet(List<GoblinArtistTopicVo> topics, LocalDateTime now) {
        List<String> artistIds = topics.stream()
                .map(GoblinArtistTopicVo::getArtistId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (artistIds.isEmpty()) {
            return Collections.emptySet();
        }
        List<GoblinArtistAuthApplyVo> auths = mongoTemplate.find(
                new Query(Criteria.where("status").is(GoblinArtistConst.APPLY_APPROVED)
                        .and("authExpireAt").gt(now)
                        .and("artistId").in(artistIds)),
                GoblinArtistAuthApplyVo.class, GoblinArtistAuthApplyVo.class.getSimpleName());
        return auths.stream()
                .map(a -> a.getStoreId() + "_" + a.getArtistId())
                .collect(Collectors.toSet());
    }

    // ======================== 私有：详情读取 ========================

    /** Redis 缓存 → MongoDB 回源（对齐 B 端 loadTopic，C 端不限店铺） */
    private GoblinArtistTopicVo loadTopic(String topicId) {
        String redisKey = GoblinRedisConst.ARTIST_TOPIC + topicId;
        Object cached = goblinRedisUtils.get(redisKey);
        if (cached instanceof GoblinArtistTopicVo) {
            GoblinArtistTopicVo topic = (GoblinArtistTopicVo) cached;
            return Objects.equals(topic.getDelFlg(), GoblinArtistConst.DEL_NO) ? topic : null;
        }
        GoblinArtistTopicVo topic = mongoTemplate.findOne(
                new Query(Criteria.where("topicId").is(topicId)
                        .and("delFlg").is(GoblinArtistConst.DEL_NO)),
                GoblinArtistTopicVo.class, GoblinArtistTopicVo.class.getSimpleName());
        if (topic != null) {
            goblinRedisUtils.set(redisKey, topic, TOPIC_TTL);
        }
        return topic;
    }

    /** 内嵌商品实时校验可售，name/图/价取实时值；支持默认/价格排序 */
    private List<GoblinFrontArtistTopicDetailVo.GoodsItem> buildGoods(
            List<GoblinArtistTopicVo.GoodsItem> embedded, String sortType, String sortOrder) {
        List<GoblinFrontArtistTopicDetailVo.GoodsItem> goods = new ArrayList<>();
        if (CollectionUtils.isEmpty(embedded)) {
            return goods;
        }
        for (GoblinArtistTopicVo.GoodsItem item : embedded) {
            GoblinGoodsInfoVo info = goblinRedisUtils.getGoodsInfoVo(item.getSpuId());
            if (!isSaleable(info)) {
                continue;
            }
            GoblinFrontArtistTopicDetailVo.GoodsItem good = new GoblinFrontArtistTopicDetailVo.GoodsItem();
            good.setSpuId(info.getSpuId());
            good.setName(info.getName());
            good.setCoverPic(info.getCoverPic());
            good.setSellPrice(info.getSellPrice());
            good.setPriceGe(info.getPriceGe());
            good.setPriceLe(info.getPriceLe());
            good.setSort(item.getSort());
            goods.add(good);
        }
        if (SORT_PRICE.equals(sortType)) {
            Comparator<BigDecimal> priceCmp = ORDER_DESC.equals(sortOrder)
                    ? Comparator.nullsLast(Comparator.reverseOrder())
                    : Comparator.nullsLast(Comparator.naturalOrder());
            goods.sort(Comparator.comparing(GoblinFrontArtistTopicDetailVo.GoodsItem::getPriceGe, priceCmp));
        } else {
            goods.sort(Comparator.comparing(GoblinFrontArtistTopicDetailVo.GoodsItem::getSort,
                    Comparator.nullsLast(Comparator.naturalOrder())));
        }
        return goods;
    }

    /** 可售口径对齐 C 端现有商品列表：未删除 + 已上架 + 非隐藏 */
    private boolean isSaleable(GoblinGoodsInfoVo info) {
        return info != null
                && "0".equals(info.getDelFlg())
                && "3".equals(info.getShelvesStatus())
                && "0".equals(info.getSpuAppear());
    }

    // ======================== 私有：列表项组装 ========================

    private Map<String, KylinArtist> artistMap(List<GoblinArtistTopicVo> topics) {
        List<String> artistIds = topics.stream()
                .map(GoblinArtistTopicVo::getArtistId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (artistIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return kylinArtistMapper.selectList(new LambdaQueryWrapper<KylinArtist>()
                        .in(KylinArtist::getArtistId, artistIds))
                .stream()
                .collect(Collectors.toMap(KylinArtist::getArtistId, a -> a, (a, b) -> a));
    }

    private List<GoblinFrontArtistTopicHomeVo.TopicItem> buildHomeItems(List<GoblinArtistTopicVo> topics) {
        Map<String, KylinArtist> artistMap = artistMap(topics);
        return topics.stream().map(t -> {
            GoblinFrontArtistTopicHomeVo.TopicItem item = new GoblinFrontArtistTopicHomeVo.TopicItem();
            item.setTopicId(t.getTopicId());
            item.setTopicName(t.getTopicName());
            item.setBannerUrl(t.getBannerUrl());
            item.setBannerHeight(t.getBannerHeight());
            item.setRecommendPosition(t.getRecommendPosition());
            item.setTag(t.getTag());
            item.setArtistId(t.getArtistId());
            KylinArtist artist = artistMap.get(t.getArtistId());
            if (artist != null) {
                item.setArtistName(artist.getArtistName());
                item.setAvatarUrl(artist.getAvatarUrl());
            }
            return item;
        }).collect(Collectors.toList());
    }

    private List<GoblinFrontArtistTopicListPageVo.TopicItem> buildListItems(List<GoblinArtistTopicVo> topics) {
        Map<String, KylinArtist> artistMap = artistMap(topics);
        return topics.stream().map(t -> {
            GoblinFrontArtistTopicListPageVo.TopicItem item = new GoblinFrontArtistTopicListPageVo.TopicItem();
            item.setTopicId(t.getTopicId());
            item.setTopicName(t.getTopicName());
            item.setBannerUrl(t.getBannerUrl());
            item.setBannerHeight(t.getBannerHeight());
            item.setRecommendPosition(t.getRecommendPosition());
            item.setTag(t.getTag());
            item.setArtistId(t.getArtistId());
            KylinArtist artist = artistMap.get(t.getArtistId());
            if (artist != null) {
                item.setArtistName(artist.getArtistName());
                item.setAvatarUrl(artist.getAvatarUrl());
            }
            return item;
        }).collect(Collectors.toList());
    }
}
