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.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.erp.security.util.SecurityUtil;
import com.zanxiang.game.module.base.pojo.dto.H5GameConfigDTO;
import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
import com.zanxiang.game.module.manage.enums.GameStatusEnum;
import com.zanxiang.game.module.manage.pojo.dto.GameAppletConfigDTO;
import com.zanxiang.game.module.manage.pojo.dto.GameAppletDTO;
import com.zanxiang.game.module.manage.pojo.dto.GameDTO;
import com.zanxiang.game.module.manage.pojo.params.GameAddParam;
import com.zanxiang.game.module.manage.pojo.params.GameListParam;
import com.zanxiang.game.module.manage.pojo.vo.GameChoiceVO;
import com.zanxiang.game.module.manage.pojo.vo.GameInfoVO;
import com.zanxiang.game.module.manage.pojo.vo.GameListVO;
import com.zanxiang.game.module.manage.service.*;
import com.zanxiang.game.module.mybatis.entity.Cp;
import com.zanxiang.game.module.mybatis.entity.Game;
import com.zanxiang.game.module.mybatis.entity.GameTag;
import com.zanxiang.game.module.mybatis.mapper.GameMapper;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.util.function.Tuple2;

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

/**
 * @author : lingfeng
 * @time : 2022-06-24
 * @description : 游戏逻辑
 */
@Slf4j
@Service
public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements IGameService {

    @Autowired
    private IGamePayWayService gamePayWayService;

    @Autowired
    private IGameTagService gameTagService;

    @Autowired
    private ICpService cpService;

    @Autowired
    private IGameAppletService gameAppletService;

    @Autowired
    private IGameAuthService gameAuthService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean gameAddOrUpdate(GameAddParam param) {
        //游戏分类处理
        String gameTags = this.getGameTags(param.getTagIdList());
        //主键id
        Long id = param.getId();
        Game game;
        if (id == null) {
            game = Game.builder()
                    .cpId(param.getCpId())
                    .name(param.getName())
                    .category(param.getCategory())
                    .tags(gameTags)
                    .status(GameStatusEnum.UN_JOIN_UP.getStatus())
                    .shareScale(param.getShareScale())
                    .h5GameId(param.getH5GameId())
                    .guideGameId(param.getGuideGameId())
                    .remark(param.getRemark())
                    .h5GameConfig(JsonUtil.toString(param.getH5GameConfigDTO()))
                    .isPut(param.getIsPut())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
        } else {
            game = super.getById(id);
            game.setCpId(param.getCpId());
            game.setName(param.getName());
            game.setTags(gameTags);
            game.setShareScale(param.getShareScale());
            game.setH5GameId(param.getH5GameId());
            game.setGuideGameId(param.getGuideGameId());
            game.setRemark(param.getRemark());
            game.setH5GameConfig(JsonUtil.toString(param.getH5GameConfigDTO()));
            game.setIsPut(param.getIsPut());
            game.setUpdateTime(LocalDateTime.now());
        }
        if (!Objects.equals(param.getIsParentGame(), Boolean.TRUE) && param.getParentGameId() != null) {
            game.setParentId(param.getParentGameId());
        }
        super.saveOrUpdate(game);
        //APP游戏不需要配置应用信息
        if (Objects.equals(param.getCategory(), GameCategoryEnum.CATEGORY_APP.getId())) {
            return Boolean.TRUE;
        }
        return gameAppletService.addOrUpdate(game, param.getGameAppletConfigDTO());
    }

    private String getGameTags(List<Long> tagIdList) {
        if (CollectionUtils.isEmpty(tagIdList)) {
            return null;
        }
        List<GameTag> gameTagList = gameTagService.listByIds(tagIdList);
        Set<Long> tagIdSet = new HashSet<>();
        gameTagList.forEach(gameTag -> {
            tagIdSet.add(gameTag.getId());
            if (Objects.equals(gameTag.getIsParent(), Boolean.TRUE) && gameTag.getParentId() != null) {
                tagIdSet.add(gameTag.getParentId());
            }
        });
        if (tagIdSet.isEmpty()) {
            return null;
        }
        return StringUtils.join(tagIdSet, ",");
    }

    @Override
    public IPage<GameListVO> gameList(GameListParam param) {
        //分类标签
        List<Long> tagIds = new ArrayList<>();
        if (param.getGameClassifyId() != null) {
            if (Objects.equals(param.getIsParentClassify(), Boolean.TRUE)) {
                tagIds = gameTagService.list(new LambdaQueryWrapper<GameTag>()
                        .eq(GameTag::getParentId, param.getGameClassifyId()))
                        .stream().map(GameTag::getId).collect(Collectors.toList());
            }
        }
        final List<Long> tagIdList = tagIds;
        //执行查询
        return page(param.toPage(), new QueryWrapper<Game>().lambda()
                .eq(param.getCpId() != null, Game::getCpId, param.getCpId())
                .eq(param.getGameId() != null && !Objects.equals(param.getIsParentGame(), Boolean.TRUE), Game::getId, param.getGameId())
                .and(param.getGameId() != null && Objects.equals(param.getIsParentGame(), Boolean.TRUE),
                        qw -> qw.eq(Game::getId, param.getGameId()).or().eq(Game::getParentId, param.getGameId()))
                .eq(param.getGameCategoryId() != null, Game::getCategory, param.getGameCategoryId())
                .eq(param.getH5GameId() != null, Game::getH5GameId, param.getH5GameId())
                .eq(param.getGuideGameId() != null, Game::getGuideGameId, param.getGuideGameId())
                .eq(param.getStatus() != null, Game::getStatus, param.getStatus())
                //非父标签查询
                .apply(param.getGameClassifyId() != null && !Objects.equals(param.getIsParentClassify(), Boolean.TRUE),
                        "FIND_IN_SET({0}, tags)", String.valueOf(param.getGameClassifyId()))
                //父标签查询
                .and(param.getGameClassifyId() != null && Objects.equals(param.getIsParentClassify(), Boolean.TRUE),
                        qw -> {
                            qw.apply("FIND_IN_SET({0}, tags)", String.valueOf(param.getGameClassifyId()));
                            for (Long tagId : tagIdList) {
                                qw.or().apply("FIND_IN_SET({0}, tags)", String.valueOf(tagId));
                            }
                        }
                )
                .orderByDesc(Game::getCreateTime)
        ).convert(this::toVo);
    }

    private GameListVO toVo(Game game) {
        GameListVO gameListVO = BeanUtil.copy(game, GameListVO.class);
        if (gameListVO == null) {
            return null;
        }
        //cp设置
        if (gameListVO.getCpId() != null) {
            Cp cp = cpService.getById(gameListVO.getCpId());
            gameListVO.setCpName(cp == null ? null : cp.getCpName());
        }
        //游戏类型
        if (gameListVO.getCategory() != null) {
            gameListVO.setCategoryName(GameCategoryEnum.getNameByCategory(gameListVO.getCategory()));
        }
        //游戏分类
        if (Strings.isNotBlank(game.getTags())) {
            List<Long> tagIdList = Arrays.stream(game.getTags().split(","))
                    .map(Long::parseLong).collect(Collectors.toList());
            gameListVO.setTagIdList(tagIdList);
            gameListVO.setTagNameList(gameTagService.listByIds(tagIdList).stream()
                    .map(GameTag::getName).collect(Collectors.toList()));
        } else {
            gameListVO.setTagIdList(Collections.emptyList());
            gameListVO.setTagNameList(Collections.emptyList());
        }
        //主游戏设置
        if (gameListVO.getParentId() != null) {
            Game parentGame = super.getById(gameListVO.getParentId());
            if (parentGame != null) {
                gameListVO.setIsParentGame(Boolean.FALSE);
                gameListVO.setParentId(parentGame.getId());
                gameListVO.setParentName(parentGame.getName());
            }
        } else {
            gameListVO.setIsParentGame(Boolean.TRUE);
        }
        //h5游戏
        if (gameListVO.getH5GameId() != null) {
            Game h5Game = super.getById(gameListVO.getH5GameId());
            gameListVO.setH5GameName(h5Game == null ? null : h5Game.getName());
        }
        //关联游戏
        if (gameListVO.getGuideGameId() != null) {
            Game guideGame = super.getById(gameListVO.getGuideGameId());
            gameListVO.setGuideGameName(guideGame == null ? null : guideGame.getName());
        }
        //查询支付方式列表
        gameListVO.setGamePayWayList(gamePayWayService.getByGameId(game.getId()));
        //游戏应用信息
        GameAppletDTO gameAppletDTO = gameAppletService.getByGameId(game.getId());
        if (gameAppletDTO != null) {
            gameListVO.setGameAppletConfigDTO(BeanUtil.copy(gameAppletDTO, GameAppletConfigDTO.class));
        }
        //H5游戏配置
        if (Strings.isNotBlank(game.getH5GameConfig())) {
            gameListVO.setH5GameConfigDTO(JsonUtil.toObj(game.getH5GameConfig(), H5GameConfigDTO.class));
        }
        return gameListVO;
    }

    @Override
    public List<GameChoiceVO> choiceList() {
        Tuple2<String, List<Long>> tuple2 = gameAuthService.getUserGameList(null);
        if (CollectionUtils.isEmpty(tuple2.getT2())) {
            return Collections.emptyList();
        }
        return super.list(new LambdaQueryWrapper<Game>()
                .in(!SecurityUtil.isAdmin(), Game::getId, tuple2.getT2())
                .select(Game::getId, Game::getName, Game::getCategory, Game::getParentId, Game::getSuperGameId))
                .stream()
                .map(game -> BeanUtil.copy(game, GameChoiceVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public GameDTO getById(Long id) {
        if (id == null) {
            return null;
        }
        return BeanUtil.copy(super.getById(id), GameDTO.class);
    }

    @Override
    public Map<Long, GameDTO> gameCondition(List<Long> gameIdList, Long cpId, Long gameId, Long gameCategoryId) {
        List<GameDTO> gameList = super.list(new LambdaQueryWrapper<Game>()
                .select(Game::getId, Game::getCpId, Game::getName, Game::getCategory, Game::getSuperGameId)
                .eq(cpId != null, Game::getCpId, cpId)
                .in(CollectionUtils.isNotEmpty(gameIdList), Game::getId, gameIdList)
                .eq(gameId != null, Game::getId, gameId)
                .eq(gameCategoryId != null, Game::getCategory, gameCategoryId)
        ).stream().map(game -> BeanUtil.copy(game, GameDTO.class)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(gameList)) {
            return Collections.emptyMap();
        }
        return gameList.stream().collect(Collectors.toMap(GameDTO::getId, Function.identity()));
    }

    @Override
    public Map<Long, GameDTO> gameMap(Collection<Long> gameIds) {
        if (CollectionUtils.isEmpty(gameIds)) {
            return Collections.emptyMap();
        }
        List<Game> gameList = super.listByIds(gameIds);
        if (CollectionUtils.isEmpty(gameList)) {
            return Collections.emptyMap();
        }
        return gameList.stream().map(game -> BeanUtil.copy(game, GameDTO.class))
                .collect(Collectors.toMap(GameDTO::getId, Function.identity()));
    }

    @Override
    public Map<Long, GameDTO> gameMap() {
        List<Game> gameList = super.list();
        if (CollectionUtils.isEmpty(gameList)) {
            return Collections.emptyMap();
        }
        return gameList.stream()
                .map(game -> BeanUtil.copy(game, GameDTO.class))
                .collect(Collectors.toMap(GameDTO::getId, Function.identity()));
    }

    @Override
    public Boolean deleteById(Long id) {
        return super.removeById(id);
    }

    @Override
    public Boolean statusUpdate(Long id, Integer status) {
        return super.update(new LambdaUpdateWrapper<Game>()
                .set(Game::getStatus, status)
                .set(Game::getUpdateTime, LocalDateTime.now())
                .eq(Game::getId, id));
    }

    @Override
    public List<GameInfoVO> infoByIds(Collection<Long> gameIds) {
        return listByIds(gameIds).stream().map(game -> BeanUtil.copy(game, GameInfoVO.class)).collect(Collectors.toList());
    }

}
