package com.fjhx.service.video.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.BaseEntity;
import com.fjhx.entity.video.VideoClassify;
import com.fjhx.mapper.video.VideoClassifyMapper;
import com.fjhx.params.video.VideoClassifyVo;
import com.fjhx.service.video.VideoClassifyService;
import com.fjhx.utils.Assert;
import com.fjhx.utils.TreeUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 分类 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-08-08
 */
@Service
public class VideoClassifyServiceImpl extends ServiceImpl<VideoClassifyMapper, VideoClassify> implements VideoClassifyService {

    @Override
    public List<JSONObject> getTree(Map<String, String> condition) {

        // 分类名称
        String name = condition.get("name");

        List<VideoClassify> list = lambdaQuery()
                .select(VideoClassify::getId, VideoClassify::getName, VideoClassify::getParentId, VideoClassify::getVideoNum)
                .like(ObjectUtil.isNotEmpty(name), VideoClassify::getName, name)
                .list();

        // 构建树形
        return TreeUtil.buildTreeObj(list);
    }

    @Override
    public void add(VideoClassifyVo classifyVo) {

        Assert.notEmpty(classifyVo.getName(), "分类名称不能为空");

        Long parentId = classifyVo.getParentId();
        if (parentId == null) {
            classifyVo.setParentId(0L);
            classifyVo.setParentIdSet(null);
        } else if (parentId == 0L) {
            classifyVo.setParentIdSet(null);
        } else {
            // 查询父级分类
            VideoClassify parentClassify = getById(parentId);
            Assert.notEmpty(parentClassify, "没有找到父级分类");

            // 赋值父级id集合
            String parentIdSet = parentClassify.getParentIdSet();
            classifyVo.setParentIdSet(
                    (ObjectUtil.isEmpty(parentIdSet) ? "" : parentIdSet + ",") + parentId);
        }

        peerNameOnly(classifyVo.getParentId(), classifyVo.getName(), null);

        classifyVo.setVideoNum(0);

        save(classifyVo);
    }

    @Override
    public void edit(VideoClassifyVo classifyVo) {
        Assert.notEmpty(classifyVo.getId(), "分类Id不能为空");
        Assert.notEmpty(classifyVo.getParentId(), "父分类id不能为空");
        Assert.notEmpty(classifyVo.getName(), "分类名称不能为空");

        peerNameOnly(classifyVo.getParentId(), classifyVo.getName(), classifyVo.getId());
        updateById(classifyVo);
    }

    @Override
    public void delete(VideoClassifyVo classifyVo) {
        Long id = classifyVo.getId();

        Assert.notEmpty(id, "分类id不能为空");

        Long childrenCount = lambdaQuery().eq(VideoClassify::getParentId, id).count();
        Assert.eqZero(childrenCount, "该分类下存在子级分类，无法删除");

        removeById(classifyVo.getId());
    }

    @Override
    public List<Long> getChildrenIdList(Long classifyId) {

        List<VideoClassify> list = lambdaQuery()
                .select(BaseEntity::getId)
                .like(VideoClassify::getParentIdSet, classifyId)
                .list();

        List<Long> result = list.stream().map(BaseEntity::getId).collect(Collectors.toList());

        result.add(0, classifyId);

        return result;
    }


    @Override
    public void updateVideoNum(Long oldClassifyId, Integer oldVideoNum, Long newClassifyId, Integer newVideoNum) {
        if (ObjectUtil.equals(oldVideoNum, newVideoNum) && ObjectUtil.equals(oldClassifyId, newClassifyId)) return;

        synchronized (this) {
            Map<Long, VideoClassify> videoClassifyMap = list().stream().collect(Collectors.toMap(BaseEntity::getId, item -> item));

            Set<VideoClassify> videoClassifies = new HashSet<>();

            // 分类相同,变更改变量即可

            if (ObjectUtil.equals(oldClassifyId, newClassifyId)) {
                // 递归寻找所有父级节点
                recursion(videoClassifies, videoClassifyMap, oldClassifyId, newVideoNum - oldVideoNum);
            }
            // 分类不相同,减去旧的数量，加上新的数量
            else {
                if (oldVideoNum != 0)
                    recursion(videoClassifies, videoClassifyMap, oldClassifyId, -oldVideoNum);

                if (newVideoNum != 0)
                    recursion(videoClassifies, videoClassifyMap, newClassifyId, newVideoNum);
            }

            boolean b = updateBatchById(videoClassifies);

            Assert.eqTrue(b, "更新分类视频数量失败");
        }
    }

    /**
     * 递归出所有需要变更数量的分类
     *
     * @param videoClassifies  需要更新视频数量的分类
     * @param videoClassifyMap key classifyId；value VideoClassify
     * @param classifyId       父级id
     * @param changeNum        变更数量
     */
    private void recursion(Set<VideoClassify> videoClassifies, Map<Long, VideoClassify> videoClassifyMap, Long classifyId, Integer changeNum) {
        VideoClassify videoClassify = videoClassifyMap.get(classifyId);
        videoClassify.setVideoNum(videoClassify.getVideoNum() + changeNum);
        videoClassifies.add(videoClassify);

        Long parentId = videoClassify.getParentId();
        if (parentId != 0) {
            recursion(videoClassifies, videoClassifyMap, parentId, changeNum);
        }

    }


    /**
     * 保证同级名称不重复
     */
    private void peerNameOnly(Long parentId, String classifyName, Long excludeId) {

        Long count = lambdaQuery()
                .eq(BaseEntity::getTenantId, AuthUtil.getTenantId())
                .eq(VideoClassify::getParentId, parentId)
                .eq(VideoClassify::getName, classifyName)
                .ne(ObjectUtil.isNotEmpty(excludeId), BaseEntity::getId, excludeId)
                .count();

        Assert.eqZero(count, "存在相同分类名称");

    }

}
