
package com.tmerclub.cloud.im.socket.app;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.bo.UidInfoBO;

import com.tmerclub.cloud.api.auth.constant.SysTypeEnum;
import com.tmerclub.cloud.api.auth.feign.AccountFeignClient;
import com.tmerclub.cloud.api.auth.feign.TokenFeignClient;
import com.tmerclub.cloud.api.auth.vo.AuthAccountVO;
import com.tmerclub.cloud.api.multishop.bo.EsShopDetailBO;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopUserFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopUserVO;
import com.tmerclub.cloud.api.platform.feign.SysUserFeignClient;
import com.tmerclub.cloud.api.platform.vo.SysUserVO;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.common.util.MapUtil;
import com.tmerclub.cloud.im.constants.Constant;
import com.tmerclub.cloud.im.constants.MsgCode;
import com.tmerclub.cloud.im.constants.SendType;
import com.tmerclub.cloud.im.model.ImMsgBizUserHistory;
import com.tmerclub.cloud.im.service.ImMsgBizSkillsService;
import com.tmerclub.cloud.im.service.ImMsgBizUserHistoryService;
import com.tmerclub.cloud.im.socket.multishop.ShopOnlineWebSocketServer;
import com.tmerclub.cloud.im.socket.multishop.ShopWebSocketServer;
import com.tmerclub.cloud.im.socket.platform.SysOnlineWebSocketServer;
import com.tmerclub.cloud.im.socket.platform.SysWebSocketServer;
import com.tmerclub.cloud.im.vo.ImMsgBizSkillsVO;
import com.tmerclub.cloud.im.vo.MessageInfoVO;
import com.tmerclub.cloud.im.vo.MsgItemVO;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 用户收到的消息
 * 10,"无法获取用户信息"
 * 11,"账户已在别处登录，请刷新"
 * 12,"对方不在线"
 * 13, "内容格式有误"
 *
 * @author Lzk
 */
@ServerEndpoint("/ua/im/websocket/{token}/{userId}")
@Component
public class UserWebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(UserWebSocketServer.class);

    /**
     * UUID为key
     */
    public static final ConcurrentHashMap<String, Session> USER_MAP = new ConcurrentHashMap<>(256);

    private static TokenFeignClient tokenFeignClient;

    private static UserFeignClient userFeignClient;

    private static SysUserFeignClient sysUserFeignClient;

    private static ShopDetailFeignClient shopDetailFeignClient;

    private static AccountFeignClient accountFeignClient;

    private static ImMsgBizUserHistoryService imMsgBizUserHistoryService;

    private static ImMsgBizSkillsService imMsgBizSkillsService;

    private static ShopUserFeignClient shopUserFeignClient;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        tokenFeignClient = applicationContext.getBean(TokenFeignClient.class);
        userFeignClient = applicationContext.getBean(UserFeignClient.class);
        sysUserFeignClient = applicationContext.getBean(SysUserFeignClient.class);
        shopDetailFeignClient = applicationContext.getBean(ShopDetailFeignClient.class);
        accountFeignClient = applicationContext.getBean(AccountFeignClient.class);
        imMsgBizUserHistoryService = applicationContext.getBean(ImMsgBizUserHistoryService.class);
        imMsgBizSkillsService = applicationContext.getBean(ImMsgBizSkillsService.class);
        shopUserFeignClient = applicationContext.getBean(ShopUserFeignClient.class);
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        token = Base64.decodeStr(token);
        UidInfoBO uidInfoBO = tokenFeignClient.checkToken(token);
        if (uidInfoBO == null) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        // 如果原来就有token
        Session oldSession = USER_MAP.get(Constant.USER_PREFIX + uidInfoBO.getUserId());
        if (oldSession != null) {
            // 客户端收到301，关闭ws链接，弹出提示
            if (oldSession.isOpen()) {
                oldSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.LOGIN_IN_OTHER_PLACE, "账户已在别处登录，请刷新")));
                oldSession.close();
            }
        }

        USER_MAP.put(Constant.USER_PREFIX + uidInfoBO.getUserId(), session);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success("ok")));
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("token") String token, @PathParam("userId") Long userId) {
        USER_MAP.remove(Constant.USER_PREFIX + userId);
    }

    /**
     * 连接错误调用的方法
     */
    @OnError
    public void onError(Session session, @PathParam("token") String token, Throwable error, @PathParam("userId") Long userId) {
        USER_MAP.remove(Constant.USER_PREFIX + userId);
        log.error("客服连接错误：{}", error);
    }

    /**
     * 收到客户端消息后调用的方法，该消息由用户发过来
     *
     * @param sourceMessage 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String sourceMessage, @PathParam("token") String token, Session session) throws IOException {
        token = Base64.decodeStr(token);
        UidInfoBO uidInfoBO = tokenFeignClient.checkToken(token);
        if (Objects.isNull(uidInfoBO)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        if (StrUtil.isBlank(sourceMessage)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        MessageInfoVO messageInfo = Json.parseObject(sourceMessage, MessageInfoVO.class);

        if (Objects.isNull(messageInfo)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        // 保持心跳
        if (StrUtil.equals(messageInfo.getContent(), Constant.HEART_BEAT)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HEART_BEAT, "保持心跳")));
            }
            return;
        }

        Long bizId = messageInfo.getToId();
        Long userId = uidInfoBO.getUserId();
        ServerResponseEntity<UserApiVO> userApiResponse = userFeignClient.getInsiderUserData(uidInfoBO.getUserId());
        if (!userApiResponse.isSuccess()) {
            throw new LuckException(userApiResponse.getMsg());
        }
        UserApiVO user = userApiResponse.getData();
        // 判断用户是发送给商家客服还是平台客服
        switch (messageInfo.getSendType()) {
            case SendType.PLATFORM:
                sendToPlatform(bizId, session, messageInfo, userId, user);
                break;
            case SendType.SHOP:
                sendToShop(bizId, session, messageInfo, userId, user);
                break;
            default:
                break;
        }
    }

    public void sendToPlatform(Long bizId, Session session, MessageInfoVO messageInfo, Long userId, UserApiVO user) throws IOException {
        ServerResponseEntity<AuthAccountVO> authAccountResponse = accountFeignClient.getBySysTypeAndIsAdminAndTenantId(SysTypeEnum.PLATFORM.value(), 1, bizId);
        if (!authAccountResponse.isSuccess()) {
            throw new LuckException(authAccountResponse.getMsg());
        }
        if (Objects.isNull(authAccountResponse.getData())) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }
        AuthAccountVO authAccount = authAccountResponse.getData();
        ServerResponseEntity<SysUserVO> sysUserResponse = sysUserFeignClient.getSysUserByUserId(authAccount.getUserId());
        if (!sysUserResponse.isSuccess()) {
            throw new LuckException(sysUserResponse.getMsg());
        }
        SysUserVO sysUser = sysUserResponse.getData();
        if (Objects.isNull(sysUser)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }
        // 获取消息历史
        if (Objects.nonNull(messageInfo.getHistory()) && Objects.equals(messageInfo.getHistory(), true)) {
            PageVO<MsgItemVO> msgItemPage = imMsgBizUserHistoryService.getUserPlatformHistory(sysUser, messageInfo, bizId, userId, user);
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HISTORY, msgItemPage)));
            }
            return;
        }
        // 标记消息已读
        if (Objects.nonNull(messageInfo.getRead()) && Objects.equals(messageInfo.getRead(), true)) {
            markIsRead(bizId, session, messageInfo, userId);
            return;
        }

        // 查出负责该客户的客服id
        Long sysUserId = null;
        if (Objects.equals(messageInfo.getOnlineOrOffline(), true) || StrUtil.isNotBlank(messageInfo.getContent())) {
            String tempSysUserId = RedisUtil.get(Constant.IN_CHARGE_SYS + userId);
            if (StrUtil.isNotBlank(tempSysUserId)) {
                sysUserId = Long.valueOf(tempSysUserId.substring(4));
            }
        }

        // 判断客服是否在线
        if (Objects.equals(messageInfo.getOnlineOrOffline(), true)) {
            sendOnlineMsg(bizId, sysUserId, session);
        }
        // 发送消息
        if (StrUtil.isNotBlank(messageInfo.getContent())) {
            log.info("发送消息给平台客服, 租户id：{}, 用户id：{}, 消息：{}", bizId, user.getUserId(), messageInfo.getContent());
            // 查出负责该客户的客服
            if (Objects.nonNull(sysUserId)) {
                Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
                if (Objects.nonNull(sysSession)) {
                    ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, sysUserId);
                    sendMsgToSysUser(bizId, messageInfo, user, sysUser, sysUserId, sysSession, imMsgBizUserHistory);
                    return;
                }
                RedisUtil.del(Constant.IN_CHARGE_SYS + userId);
            }
            // 如果没有跟进的客服或者跟进的客服不在线
            List<String> keys = MapUtil.getKeysByKeyPrefix(SysWebSocketServer.SYS_MAP, Constant.SYS_PREFIX);
            if (CollUtil.isNotEmpty(keys)) {
                getNewOnlineSysUser(bizId, messageInfo, userId, user, sysUser, keys);
            } else {
                ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, authAccount.getUserId());
                List<Session> onlineSysUser = MapUtil.getSessionByKeyPrefix(SysOnlineWebSocketServer.SYS_ONLINE_MAP, Constant.ONLINE_SYS_PREFIX);
                sendNewMsg(onlineSysUser, imMsgBizUserHistory.getEmployeeId(), Constant.UNREAD_SYS_PREFIX);
            }
        }
        messagePlatform(bizId, messageInfo, user, (long) com.tmerclub.cloud.common.constant.Constant.SUPER_ADMIN_ID, null);
    }

    private void sendMsgToSysUser(Long bizId, MessageInfoVO messageInfo, UserApiVO user, SysUserVO sysUser, Long sysUserId, Session sysSession, ImMsgBizUserHistory imMsgBizUserHistory) throws IOException {
        // 发送消息给平台
        imMsgBizUserHistory.setNickName(sysUser.getNickName());
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
        if (sysSession.isOpen()) {
            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            messagePlatform(bizId, messageInfo, user, sysUserId, sysSession);
        }
    }

    private static Long getNewOnlineSysUser(Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, SysUserVO sysUser, List<String> listSysUser) throws IOException {
        // 随机选一个在线客服
        int index = (int) (Math.random() * listSysUser.size());
        long tempLength = (Constant.SYS_PREFIX).length();
        Long sysUserId = Long.valueOf(listSysUser.get(index).substring((int) tempLength));
        Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
        RedisUtil.set(Constant.IN_CHARGE_SYS + userId, "test" + sysUserId, 0);
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserPlatformHistory(messageInfo, bizId, userId, sysUserId);
        // 发送消息给平台
        imMsgBizUserHistory.setNickName(sysUser.getNickName());
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
        if (Objects.nonNull(sysSession)) {
            if (sysSession.isOpen()) {
                sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            }
        }
        return sysUserId;
    }

    private static void sendOnlineMsg(Long bizId, Long sysUserId, Session session) throws IOException {

        // 1.没有指定的客服就直接查店铺中是否有在线的客服（后面发送消息的步骤中会分配一个客服）
        String sysUserKey = Constant.ONLINE_SYS_PREFIX;
        if (Objects.nonNull(sysUserId)) {
            // 2.如果用户有沟通中的客服，则直接查询该客服是否在线
            sysUserKey = sysUserKey + sysUserId + Constant.UNDERLINE;
        }

        Boolean isExist = MapUtil.isExistKeyPrefix(SysOnlineWebSocketServer.SYS_ONLINE_MAP, sysUserKey);
        MsgItemVO msgItem = new MsgItemVO();
        msgItem.setOnlineOrOffline(isExist);
        msgItem.setChatType(SendType.PLATFORM);
        msgItem.setShopId(bizId);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.ONLINE_OR_OFFLINE, msgItem)));
        }
    }

    /**
     * 用户-平台消息
     * @param bizId
     * @param session
     * @param messageInfo
     * @param userId
     * @throws IOException
     */
    private static void markIsRead(Long bizId, Session session, MessageInfoVO messageInfo, Long userId) throws IOException {
        if (Objects.nonNull(messageInfo.getMsgIds()) && !messageInfo.getMsgIds().isEmpty()) {
            int updateNum = imMsgBizUserHistoryService.markUserPlatformRead(userId);
            // 未读消息变更为已读消息的数量大于0
            if (updateNum > 0) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success("ok")));
                }
                if (Objects.nonNull(messageInfo.getReadNoticePlatformUserId())) {
                    Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + messageInfo.getReadNoticePlatformUserId());
                    if (Objects.nonNull(sysSession)) {
                        // 如果平台端客服在线，则发送用户消息已读提醒
                        if (sysSession.isOpen()) {
                            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                        }
                    }
                } else {
                    String tempSysUserId = RedisUtil.get(Constant.IN_CHARGE_SYS + userId);
                    if (Objects.nonNull(tempSysUserId)) {
                        long sysUserId = Long.parseLong(tempSysUserId.substring(4));
                        Session sysSession = SysWebSocketServer.SYS_MAP.get(Constant.SYS_PREFIX + sysUserId);
                        if (Objects.nonNull(sysSession)) {
                            if (sysSession.isOpen()) {
                                sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                            }
                        }
                    }
                }
            }
        }
    }

    private static void sendNewMsg(List<Session> listSysUser2, Long employeeId, String key) throws IOException {
        if (!listSysUser2.isEmpty()) {
            // 有新消息提示为半个小时
            RedisUtil.set(key + employeeId + Constant.UNDERLINE, 1, 1800);
            MsgItemVO msgItem2 = new MsgItemVO();
            msgItem2.setNewMessage(true);
            for (Session sysSession2 : listSysUser2) {
                if (Objects.nonNull(sysSession2)) {
                    if (sysSession2.isOpen()) {
                        sysSession2.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem2)));
                        RedisUtil.del(key + employeeId + Constant.UNDERLINE);
                    }
                }
            }
        }
    }

    public void sendToShop(Long bizId, Session session, MessageInfoVO messageInfo, Long userId, UserApiVO user) throws IOException {
        ServerResponseEntity<AuthAccountVO> authAccountResponse = accountFeignClient.getBySysTypeAndIsAdminAndTenantId(SysTypeEnum.MULTISHOP.value(), 1, bizId);
        if (!authAccountResponse.isSuccess()) {
            throw new LuckException(authAccountResponse.getMsg());
        }
        AuthAccountVO authAccount = authAccountResponse.getData();

        if (Objects.isNull(authAccount)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }

        ServerResponseEntity<EsShopDetailBO> shopResponse = shopDetailFeignClient.getShopByShopId(bizId);
        if (!shopResponse.isSuccess()) {
            throw new LuckException(shopResponse.getMsg());
        }
        EsShopDetailBO shopDetail = shopResponse.getData();

        if (Objects.isNull(shopDetail)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.PARAM_ERROR, "参数有误")));
            }
            return;
        }

        // 获取消息历史
        if (Objects.nonNull(messageInfo.getHistory()) && Objects.equals(messageInfo.getHistory(), true)) {
            PageVO<MsgItemVO> msgItemPage = imMsgBizUserHistoryService.getUserShopHistory(shopDetail, messageInfo, bizId, userId, user);
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HISTORY, msgItemPage)));
            }
            return;
        }

        // 标记消息已读
        if (Objects.nonNull(messageInfo.getRead()) && Objects.equals(messageInfo.getRead(), true)) {
            markShopMsgIsRead(bizId, session, messageInfo, userId);
            return;
        }


        Long employeeId = null;
        // 查出负责该客户的客服id
        if (Objects.equals(messageInfo.getOnlineOrOffline(), true) || StrUtil.isNotBlank(messageInfo.getContent())) {
            String tempEmployeeId = RedisUtil.get(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
            if (Objects.nonNull(tempEmployeeId)) {
                employeeId = Long.valueOf(tempEmployeeId.substring(4));
            }
        }

        // 判断客服是否在线
        if (Objects.equals(messageInfo.getOnlineOrOffline(), true)) {
            sendShopOnlineMsg(bizId, employeeId, session);
        }

        // 发送消息
        if (StrUtil.isNotBlank(messageInfo.getContent())) {
            log.info("发送消息给店铺客服, 租户id：{}, 用户id：{}, 消息：{}", bizId, user.getUserId(), messageInfo.getContent());
            shopSendMessage(bizId, employeeId, messageInfo, userId, user, authAccount, shopDetail);
        }
    }

    private void shopSendMessage(Long bizId, Long employeeId, MessageInfoVO messageInfo, Long userId, UserApiVO user, AuthAccountVO authAccount, EsShopDetailBO shopDetail) throws IOException {
        // 查出负责该客户的客服

        if (Objects.nonNull(employeeId)) {
            Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
            if (Objects.nonNull(shopSession)) {
                log.info("客服在线");
                getOnlineShopUser(bizId, messageInfo, userId, user, shopDetail, employeeId, shopSession);
                return;
            } else {
                log.info("客服不在线，给客服发送未读消息");
                List<Session> onlineShopEmployee = MapUtil.getSessionByKeyPrefix(ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP,
                        Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId + Constant.UNDERLINE);
                if (!onlineShopEmployee.isEmpty()) {
                    imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, employeeId);
                    RedisUtil.set(Constant.UNREAD_SHOP_PREFIX + employeeId + Constant.UNDERLINE, 1, 1800);
                    MsgItemVO newMsg = new MsgItemVO();
                    newMsg.setNewMessage(true);
                    for (Session onlineShopSession : onlineShopEmployee) {
                        if (Objects.nonNull(onlineShopSession)) {
                            if (onlineShopSession.isOpen()) {
                                onlineShopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(newMsg)));
                                RedisUtil.del(Constant.UNREAD_SHOP_PREFIX + employeeId + Constant.UNDERLINE);
                            }
                        }
                    }
                    messageShop(bizId, messageInfo, user, employeeId, null, shopDetail);
                    return;
                }
            }
            RedisUtil.del(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
        }
        // 如果没有跟进的客服或者跟进的客服不在线
        log.info("如果没有跟进的客服或者跟进的客服不在线");
        List<String> keys = MapUtil.getKeysByKeyPrefix(ShopWebSocketServer.SHOP_EMPLOYEE_MAP, Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE);
        if (CollUtil.isNotEmpty(keys)) {
            // 分配一个客服
            getNewOnlineShopUser(authAccount.getUserId(), bizId, messageInfo, userId, user, shopDetail, keys);
        } else {
            ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, authAccount.getUserId());
            List<Session> onlineEmployee = MapUtil.getSessionByKeyPrefix(ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP, Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE);
            sendNewMsg(onlineEmployee, imMsgBizUserHistory.getEmployeeId(), Constant.UNREAD_SHOP_PREFIX);
        }
        Long shopUserId = shopUserFeignClient.getShopUserIdByShopId(bizId).getData();
        messageShop(bizId, messageInfo, user, shopUserId, null, shopDetail);
    }

    private void getOnlineShopUser(Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, EsShopDetailBO shopDetail, Long employeeId, Session shopSession) throws IOException {
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, employeeId);

        // 获取客服昵称
        ServerResponseEntity<ShopUserVO> shopUserResponse = shopDetailFeignClient.getShopUserByShopUserId(employeeId);
        if (!shopUserResponse.isSuccess() || Objects.isNull(shopUserResponse.getData())) {
            throw new LuckException(shopUserResponse.getMsg());
        }
        ShopUserVO shopUserVO = shopUserResponse.getData();
        imMsgBizUserHistory.setNickName(shopUserVO.getNickName());
        // 发送消息给客服
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
        if (shopSession.isOpen()) {
            shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            messageShop(bizId, messageInfo, user, employeeId, shopSession, shopDetail);
        }
    }

    private static void getNewOnlineShopUser(Long shopEmployeeId, Long bizId, MessageInfoVO messageInfo, Long userId, UserApiVO user, EsShopDetailBO shopDetail, List<String> listEmployee) throws IOException {
        // 随机选一个在线客服
        int index = (int) (Math.random() * listEmployee.size());
        long tempLength = (Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE).length();
        Long employeeId = Long.valueOf(listEmployee.get(index).substring((int) tempLength));
        Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
        RedisUtil.set(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId, "test" + employeeId, 0);
        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveUserShopHistory(messageInfo, bizId, userId, employeeId);

        // 获取客服昵称
        ServerResponseEntity<ShopUserVO> shopUserResponse = shopDetailFeignClient.getShopUserByShopUserId(shopEmployeeId);
        if (!shopUserResponse.isSuccess()) {
            throw new LuckException(shopUserResponse.getMsg());
        }
        ShopUserVO shopUserVO = shopUserResponse.getData();
        imMsgBizUserHistory.setNickName(shopUserVO.getNickName());

        // 发送消息给客服
        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
        if (Objects.nonNull(shopSession)) {
            if (shopSession.isOpen()) {
                shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
            }
        }
    }

    private static void sendShopOnlineMsg(Long bizId, Long employeeId, Session session) throws IOException {
        // 1.没有指定的客服就直接查店铺中是否有在线的客服（后面发送消息的步骤中会分配一个客服）
        String employeeKey = Constant.ONLINE_SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE;
        if (Objects.nonNull(employeeId)) {
            // 2.如果用户有沟通中的客服，则直接查询该客服是否在线
            employeeKey = employeeKey + employeeId + Constant.UNDERLINE;
        }
        Boolean isExist = MapUtil.isExistKeyPrefix(ShopOnlineWebSocketServer.SHOP_ONLINE_EMPLOYEE_MAP, employeeKey);
        MsgItemVO msgItem = new MsgItemVO();
        msgItem.setChatType(SendType.SHOP);
        msgItem.setShopId(bizId);
        msgItem.setOnlineOrOffline(isExist);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.ONLINE_OR_OFFLINE, msgItem)));
        }
    }

    /**
     * 用户-店铺消息
     * @param bizId
     * @param session
     * @param messageInfo
     * @param userId
     * @throws IOException
     */
    private static void markShopMsgIsRead(Long bizId, Session session, MessageInfoVO messageInfo, Long userId) throws IOException {
        if (Objects.nonNull(messageInfo.getMsgIds()) && !messageInfo.getMsgIds().isEmpty()) {
            int updateNum = imMsgBizUserHistoryService.markUserShopRead(bizId, userId);
            if (updateNum > 0) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, "ok")));
                }
                if (Objects.nonNull(messageInfo.getReadNoticeEmployeeId())) {
                    Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + messageInfo.getReadNoticeEmployeeId());
                    if (Objects.nonNull(shopSession)) {
                        if (shopSession.isOpen()) {
                            shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                        }
                    }
                } else {
                    String tempEmployeeId = RedisUtil.get(Constant.IN_CHARGE_SHOP + bizId + Constant.UNDERLINE + userId);
                    if (Objects.nonNull(tempEmployeeId)) {
                        long employeeId = Long.parseLong(tempEmployeeId.substring(4));
                        Session shopSession = ShopWebSocketServer.SHOP_EMPLOYEE_MAP.get(Constant.SHOP_EMPLOYEE_PREFIX + bizId + Constant.UNDERLINE + employeeId);
                        if (Objects.nonNull(shopSession)) {
                            if (shopSession.isOpen()) {
                                shopSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                            }
                        }
                    }
                }
            }
        }
    }

    private void messageShop(Long bizId, MessageInfoVO messageInfo, UserApiVO user, Long employeeId, Session shopSession, EsShopDetailBO shopDetail) throws IOException {
        String content = messageInfo.getContent();
        if (content != null && !content.contains(Constant.BRACE_LEFT) && !content.contains(Constant.BRACE_RIGHT) && !content.contains(Constant.IM)
                && !content.contains(".jpg") && !content.contains(".png") && !content.contains(".gif")
                && !"/".equals(content.substring(0, 1))) {
            List<ImMsgBizSkillsVO> imMsgBizSkills = imMsgBizSkillsService.getByShopId(bizId);
            if (CollUtil.isNotEmpty(imMsgBizSkills)) {
                Map<String, String> collect = imMsgBizSkills.stream().collect(Collectors.toMap(ImMsgBizSkillsVO::getKeywords, ImMsgBizSkillsVO::getContent));
                for (Map.Entry<String, String> entry : collect.entrySet()) {
                    if (content.contains(entry.getKey())) {
                        log.info("商家客服自动回复关键字：{}", entry.getKey());
                        MessageInfoVO msg = new MessageInfoVO();
                        msg.setMsgType(0);
                        msg.setToId(user.getUserId());
                        msg.setContent(entry.getValue());
                        UidInfoBO uidInfoBO = new UidInfoBO();
                        uidInfoBO.setTenantId(bizId);
                        uidInfoBO.setUserId(employeeId);
                        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.saveShopUserHistory(msg, uidInfoBO);
                        // 补充自动回复者信息
                        AuthAccountVO accountVO = accountFeignClient.getByUserIdAndSysType(employeeId, SysTypeEnum.MULTISHOP.value()).getData();
                        if (Objects.nonNull(accountVO)) {
                            imMsgBizUserHistory.setNickName(accountVO.getUsername());
                        }
                        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserShopMsgItem(shopDetail, user, imMsgBizUserHistory);
                        // 在线的话发送消息，不在线的话留言
                        sendMsgUser(shopSession, msg, msgItem);
                    }
                }
            } else {
                log.info("客服自动回复列表为空，店铺id：{}", bizId);
            }
        }
    }

    private void messagePlatform(Long bizId, MessageInfoVO messageInfo, UserApiVO user, Long employeeId, Session sysSession) throws IOException {
        String content = messageInfo.getContent();
        log.info("平台客服自动回复: {}", content);
        if (content != null && !content.contains(Constant.BRACE_LEFT) && !content.contains(Constant.BRACE_RIGHT) && !content.contains(Constant.IM)
                && !content.contains(".jpg") && !content.contains(".png") && !content.contains(".gif")
                && !"/".equals(content.substring(0, 1))) {
            List<ImMsgBizSkillsVO> imMsgBizSkills = imMsgBizSkillsService.getByShopId(bizId);
            log.info("平台客服自动回复集合大小：{}， 是否为空：{}", imMsgBizSkills.size(), CollUtil.isNotEmpty(imMsgBizSkills));
            if (CollUtil.isNotEmpty(imMsgBizSkills)) {
                Map<String, String> collect = imMsgBizSkills.stream().collect(Collectors.toMap(ImMsgBizSkillsVO::getKeywords, ImMsgBizSkillsVO::getContent));
                log.info("平台客服自动回复, 关键字回复集合：{}", collect);
                for (Map.Entry<String, String> entry : collect.entrySet()) {
                    if (content.contains(entry.getKey())) {
                        log.info("平台客服自动回复关键字：{}", entry.getKey());
                        MessageInfoVO msg = new MessageInfoVO();
                        msg.setMsgType(0);
                        msg.setToId(user.getUserId());
                        msg.setContent(entry.getValue());
                        UidInfoBO uidInfoBO = new UidInfoBO();
                        uidInfoBO.setUserId(employeeId);
                        ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.savePlatformUserHistory(msg, uidInfoBO);
                        // 补充自动回复者信息
                        AuthAccountVO accountVO = accountFeignClient.getByUserIdAndSysType(employeeId, SysTypeEnum.PLATFORM.value()).getData();
                        if (Objects.nonNull(accountVO)) {
                            imMsgBizUserHistory.setNickName(accountVO.getUsername());
                        }
                        MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
                        sendMsgUser(sysSession, msg, msgItem);
                    }
                }
            } else {
                log.info("客服自动回复列表为空，店铺id：{}", bizId);
            }
        }
    }

    private static void sendMsgUser(Session sysSession, MessageInfoVO msg, MsgItemVO msgItem) throws IOException {
        Session userSession = USER_MAP.get(Constant.USER_PREFIX + msg.getToId());
        log.info("在线的话发送消息，不在线的话留言, 用户id：{}", msgItem.getUserId());
        if (userSession.isOpen()) {
            log.info("发送消息给给用户");
            userSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
        }
        if (sysSession != null) {
            log.info("发送消息给给平台或商家");
            sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
        }
    }


}
