package com.zanxiang.game.module.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.erp.security.util.SecurityUtil;
import com.zanxiang.game.module.manage.pojo.dto.GameTagDTO;
import com.zanxiang.game.module.manage.pojo.params.GameTagAddUpdateParam;
import com.zanxiang.game.module.manage.pojo.params.GameTagListParam;
import com.zanxiang.game.module.manage.pojo.vo.GameTagChoiceVO;
import com.zanxiang.game.module.manage.pojo.vo.GameTagVO;
import com.zanxiang.game.module.manage.service.IGameTagService;
import com.zanxiang.game.module.mybatis.entity.GameTag;
import com.zanxiang.game.module.mybatis.mapper.GameTagMapper;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2022-11-16
 * @description : 游戏分类标签
 */
@Slf4j
@Service
public class GameTagServiceImpl extends ServiceImpl<GameTagMapper, GameTag> implements IGameTagService {

    @Override
    public List<GameTagChoiceVO> gameTagsChoiceList() {
        return super.list().stream().map(gameTag -> BeanUtil.copy(gameTag, GameTagChoiceVO.class)).collect(Collectors.toList());
    }

    @Override
    public Map<Long, GameTagDTO> gameTagMap() {
        List<GameTag> gameTagList = list(new LambdaQueryWrapper<GameTag>()
                .select(GameTag::getId, GameTag::getName));
        if (CollectionUtils.isEmpty(gameTagList)) {
            return Collections.emptyMap();
        }
        List<GameTagDTO> gameTagDTOList = gameTagList.stream().map(gameTag -> BeanUtil.copy(gameTag, GameTagDTO.class))
                .collect(Collectors.toList());
        return gameTagDTOList.stream().collect(Collectors.toMap(GameTagDTO::getId, Function.identity()));
    }

    @Override
    public IPage<GameTagVO> list(GameTagListParam param) {
        //模糊查询父标签列表
        List<GameTag> categoryList = new ArrayList<>();
        if (Strings.isNotBlank(param.getLabelName()) && Objects.equals(param.getIsParent(), Boolean.TRUE)) {
            categoryList = super.list(new LambdaQueryWrapper<GameTag>()
                    .like(GameTag::getName, param.getLabelName())
                    .eq(GameTag::getIsParent, Boolean.TRUE));
            //查询父标签, 但是却查不到, 直接返回空
            if (categoryList.isEmpty()) {
                return new Page<>(param.getPageNum(), param.getPageSize());
            }
        }
        List<Long> parentIdList = categoryList.stream().map(GameTag::getId).collect(Collectors.toList());
        return page(param.toPage(), new QueryWrapper<GameTag>().lambda()
                //条件不为空没勾选父标签
                .like(Strings.isNotBlank(param.getLabelName()) && !Objects.equals(param.getIsParent(), Boolean.TRUE),
                        GameTag::getName, param.getLabelName())
                //条件为空查询所有父标签
                .eq(Strings.isBlank(param.getLabelName()) && Objects.equals(param.getIsParent(), Boolean.TRUE),
                        GameTag::getIsParent, Boolean.TRUE)
                //条件不为空查询父标签
                .and(Strings.isNotBlank(param.getLabelName()) && Objects.equals(param.getIsParent(), Boolean.TRUE),
                        qw -> qw.in(GameTag::getParentId, parentIdList).or().like(GameTag::getName, param.getLabelName()))
                .orderByDesc(GameTag::getCreateTime))
                .convert(this::toVo);
    }

    private GameTagVO toVo(GameTag gameTag) {
        GameTagVO gameTagVO = BeanUtil.copy(gameTag, GameTagVO.class);
        if (Objects.isNull(gameTagVO)) {
            return null;
        }
        if (Objects.equals(gameTag.getIsParent(), Boolean.TRUE)) {
            gameTagVO.setParentName(gameTagVO.getName());
        } else {
            GameTag parentGameTag = super.getById(gameTag.getParentId());
            if (parentGameTag != null) {
                gameTagVO.setParentName(parentGameTag.getName());
            }
        }
        return gameTagVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addOrUpdate(GameTagAddUpdateParam param) {
        Long id = param.getId();
        //更新
        if (id != null) {
            GameTag gameTag = super.getById(id);
            if (gameTag == null) {
                throw new BaseException("参数错误, 游戏分类标签信息不存在");
            }
            //更新标签名字, 不可重复
            if (!Objects.equals(gameTag.getName(), param.getName())) {
                //判断cp名称是否已经存在
                long count = super.count(new LambdaQueryWrapper<GameTag>()
                        .eq(GameTag::getName, param.getName()));
                if (count > 0) {
                    throw new BaseException("游戏分类标签名称已经存在");
                }
            }
            gameTag.setIsParent(param.getParentId() == null);
            gameTag.setParentId(param.getParentId());
            gameTag.setName(param.getName());
            gameTag.setRemark(param.getRemark());
            gameTag.setUpdateTime(LocalDateTime.now());
            return super.updateById(gameTag);
        }
        //判断cp名称是否已经存在
        long count = super.count(new LambdaQueryWrapper<GameTag>()
                .eq(GameTag::getName, param.getName()));
        if (count > 0) {
            throw new BaseException("游戏分类标签名称已经存在");
        }
        //创建
        return super.save(GameTag.builder()
                .name(param.getName())
                .remark(param.getRemark())
                .isParent(param.getParentId() == null)
                .parentId(param.getParentId())
                .operatorId(SecurityUtil.getUserId())
                .operatorName(SecurityUtil.getTokenInfo().getNickname())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        return super.removeById(id);
    }
}
