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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
import com.zanxiang.game.module.manage.pojo.params.GameUserChatListParam;
import com.zanxiang.game.module.manage.pojo.vo.GameUserChatVO;
import com.zanxiang.game.module.manage.service.*;
import com.zanxiang.game.module.mybatis.entity.*;
import com.zanxiang.game.module.mybatis.mapper.GameUserChatMapper;
import com.zanxiang.module.util.DateUtil;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2025-03-12
 * @description : 角色聊天记录
 */
@Slf4j
@Service
public class GameUserChatServiceImpl extends ServiceImpl<GameUserChatMapper, GameUserChat> implements IGameUserChatService {

    @Autowired
    private IGameService gameService;

    @Autowired
    private IGameServerService gameServerService;

    @Autowired
    private IGameSupperService gameSupperService;

    @Autowired
    private IGameUserRoleService gameUserRoleService;

    @Override
    public Map<Long, String> chatGameMap() {
        return Collections.singletonMap(12L, "仙剑");
    }

    @Override
    public Map<String, String> chatGameServerMap(Long supperGameId) {
        return gameServerService.list(new LambdaQueryWrapper<GameServer>()
                .select(GameServer::getServerId, GameServer::getServerName)
                .eq(GameServer::getGameId, supperGameId)
                .eq(GameServer::getIsSourceServer, Boolean.TRUE)
                .orderByDesc(GameServer::getCreateTime)
        ).stream().collect(Collectors.toMap(GameServer::getServerId, GameServer::getServerName));
    }

    @Override
    public IPage<GameUserChatVO> listOfPage(GameUserChatListParam param) {
        GameSupper gameSupper = gameSupperService.getById(param.getSupperGameId());
        return super.page(param.toPage(), new LambdaQueryWrapper<GameUserChat>()
                .eq(GameUserChat::getSupperGameId, param.getSupperGameId())
                .eq(Strings.isNotBlank(param.getRoleId()), GameUserChat::getRoleId, param.getRoleId())
                .like(Strings.isNotBlank(param.getRoleName()), GameUserChat::getRoleName, param.getRoleName())
                .eq(Strings.isNotBlank(param.getServerId()), GameUserChat::getServerId, param.getServerId())
                .ge(param.getChatStart() != null, GameUserChat::getChatTime,
                        param.getChatStart() == null ? null : LocalDateTime.of(param.getChatStart(), LocalTime.MIN))
                .le(param.getChatEnd() != null, GameUserChat::getChatTime,
                        param.getChatEnd() == null ? null : LocalDateTime.of(param.getChatEnd(), LocalTime.MAX))
                .orderByDesc(GameUserChat::getCreateTime)
        ).convert(c -> this.toVO(gameSupper, c));
    }

    private GameUserChatVO toVO(GameSupper gameSupper, GameUserChat gameUserChat) {
        if (gameUserChat == null) {
            return null;
        }
        GameUserChatVO vo = BeanUtil.copy(gameUserChat, GameUserChatVO.class);
        if (gameSupper != null) {
            vo.setGameName(gameSupper.getName());
        }
        return vo;
    }

    @Override
    public void addGameUserChat(ChatSubmitParam param) {
        List<Long> gameIdList = getGameIdBySuperGameId(param.getGameId());
        if (CollectionUtils.isEmpty(gameIdList)) {
            return;
        }
        //构造聊天记录对象
        GameUserChat chat = this.transform(param);
        //补充玩家公会信息, 区服信息
        this.processRoleInfo(gameIdList, chat.getRoleId(), chat::setGuildId, chat::setGuildName,
                role -> {
                    chat.setServerId(role.getServerId());
                    chat.setServerName(role.getServerName());
                    if (Strings.isBlank(chat.getRoleName())) {
                        chat.setRoleName(role.getRoleName());
                    }
                });
        //补充被私聊玩家公会信息, 区服信息
        this.processRoleInfo(gameIdList, chat.getChatRoleId(), chat::setChatRoleGuildId, chat::setChatRoleGuildName,
                role -> {
                    chat.setChatRoleName(role.getRoleName());
                    chat.setChatRoleServerName(role.getServerName());
                    if (Strings.isBlank(chat.getServerId())) {
                        chat.setChatRoleServerId(role.getServerId());
                    }
                });
        //保存聊天记录
        super.save(chat);
    }

    private void processRoleInfo(List<Long> gameIds, String roleId, Consumer<String> guildIdSetter,
                                 Consumer<String> guildNameSetter, Consumer<GameUserRole> serverInfoSetter) {
        if (Strings.isBlank(roleId)) {
            return;
        }
        Optional.ofNullable(this.getGameUserRole(gameIds, roleId))
                .ifPresent(gameUserRole -> {
                    if (Strings.isNotBlank(gameUserRole.getExtra())) {
                        Optional.ofNullable(JsonUtil.toMap(gameUserRole.getExtra(), Map.class, String.class))
                                .ifPresent(extraMap -> {
                                    Optional.ofNullable(extraMap.get("countryId"))
                                            .filter(Strings::isNotBlank)
                                            .ifPresent(guildIdSetter);
                                    Optional.ofNullable(extraMap.get("country"))
                                            .filter(Strings::isNotBlank)
                                            .ifPresent(guildNameSetter);
                                });
                    }
                    serverInfoSetter.accept(gameUserRole);
                });
    }

    private List<Long> getGameIdBySuperGameId(Long superGameId) {
        return gameService.list(new LambdaQueryWrapper<Game>()
                .select(Game::getId)
                .eq(Game::getSuperGameId, superGameId)
        ).stream().map(Game::getId).collect(Collectors.toList());
    }

    private GameUserRole getGameUserRole(List<Long> gameIdList, String roleId) {
        return gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getRoleId, roleId)
                .in(GameUserRole::getGameId, gameIdList)
                .orderByDesc(GameUserRole::getUpdateTime)
                .last("LIMIT 1"));
    }

    private GameUserChat transform(ChatSubmitParam param) {
        Map<String, Object> chatContentMap = param.getChatContentMap();
        return GameUserChat.builder()
                .supperGameId(param.getGameId())
                .serverId(param.getServerId())
                .roleId(chatContentMap.containsKey("role_id") ? chatContentMap.get("role_id").toString() : null)
                .roleName(chatContentMap.containsKey("role_name") ? chatContentMap.get("role_name").toString() : null)
                .chatTime(chatContentMap.containsKey("chatTime") ? DateUtil.parseLocalDateTime(chatContentMap.get("chatTime").toString()) : null)
                .content(chatContentMap.containsKey("content") ? chatContentMap.get("content").toString() : null)
                .channel(chatContentMap.containsKey("channel") ? chatContentMap.get("channel").toString() : null)
                .chatRoleId(chatContentMap.containsKey("chat_role_id") ? chatContentMap.get("chat_role_id").toString() : null)
                .chatRoleServerId(chatContentMap.containsKey("chat_role_server_id") ? chatContentMap.get("chat_role_server_id").toString() : null)
                .sourceData(JsonUtil.toString(param))
                .createTime(LocalDateTime.now())
                .build();
    }
}
