package com.ruoyi.cai.ws.processon;

import cn.hutool.core.date.DateUtil;
import com.ruoyi.cai.trd.Agora;
import com.ruoyi.cai.executor.ExecutorConstant;
import com.ruoyi.cai.service.AnchorService;
import com.ruoyi.cai.service.UserService;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.*;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
import com.ruoyi.cai.ws.constant.UserDataConstant;
import com.ruoyi.cai.ws.dto.WsRMsgGen;
import com.ruoyi.cai.ws.service.CheckConnectionDTO;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.cai.ws.util.MapGetUtil;
import com.ruoyi.cai.ws.util.RoomWebSocketUtil;
import com.ruoyi.cai.ws.util.WsExceptionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class OpenLogic {
    @Autowired
    private RoomService roomService;
    @Autowired
    private FdCtxDataCache fdCtxDataCache;
    @Autowired
    private RoomCtxCache roomCtxCache;
    @Autowired
    private UserDataCache userDataCache;
    @Autowired
    private RoomDataCache roomDataCache;
    @Autowired
    private OnlineDataCache onlineDataCache;
    @Autowired
    private UserService userService;
    @Autowired
    private AnchorService anchorService;
    @Autowired
    private Agora agora;

    public void processOn(WebSocketSession session) {
        Map<String, Object> map = session.getAttributes();
        String token = MapGetUtil.getString(map.get("token"));
        Long roomId = MapGetUtil.getLong(map.get("roomId"));
        Long userId = MapGetUtil.getLong(map.get("userId"));
        // 校验token
        process(token,roomId,userId);
    }

    public void process(String sessionKey,Long roomId,Long userId){
        Room room = roomService.load(roomId);
        if(room == null || (room.getCallUserData().getId().equals(userId) && room.getReceiverUserData().getId().equals(userId))){
            WsExceptionUtil.throwException(sessionKey,"房间不可用", HangUpEnums.OTHER,roomId);
            return;
        }
        CheckConnectionDTO checkConnect = roomService.checkConnect(room);
        if(checkConnect != null){
            WsExceptionUtil.throwException(sessionKey,checkConnect.getMessage(),checkConnect.getHangUpEnums(),roomId);
            return;
        }
        if(userId.equals(room.getCallUserData().getId())){
            // 走主叫方逻辑
            callerConnection(sessionKey,room,userId);
        }else {
            // 走接收方逻辑
            receiverConnection(sessionKey,room,userId);
        }
        // 保存上下文到redis
        FdCtxData fdCtxData = new FdCtxData();
        fdCtxData.setSessionKey(sessionKey);
        fdCtxData.setRoomId(room.getRoomId());
        fdCtxData.setUserId(userId);
        if(userId.equals(room.getCallUserData().getId())){
            fdCtxData.setUserType(UserDataConstant.TYPE_CALLER);
            fdCtxData.setTarUserId(room.getReceiverUserData().getId());
            fdCtxData.setTarUserType(UserDataConstant.TYPE_RECEIVER);
        } else {
            fdCtxData.setUserType(UserDataConstant.TYPE_RECEIVER);
            fdCtxData.setTarUserId(room.getCallUserData().getId());
            fdCtxData.setTarUserType(UserDataConstant.TYPE_CALLER);
        }
        fdCtxDataCache.save(fdCtxData);
        roomCtxCache.addFd(sessionKey,roomId,fdCtxData.getUserType());
    }

    public void callerConnection(String sessionKey,Room room,Long userId){
        boolean isFirst = false;
        Integer status = room.getStatus();
        // 首次链接
        if(RoomStatusEnums.STATUS_CREATE.getCode().equals(status)){
            // 更新缓存
            Map<String,Object> map = new HashMap<>();
            map.put("connectTime", DateUtil.currentSeconds());
            map.put("heartTime",DateUtil.currentSeconds());
            userDataCache.hMSet(room.getRoomId(), UserDataConstant.TYPE_CALLER,map);
            roomDataCache.setStatus(room.getRoomId(),RoomStatusEnums.STATUS_CALLER_CONNECT);
            onlineDataCache.add(room.getRoomId());
            userService.updateVideoStatus(userId,1);
            isFirst = true;
        }
        // 已经接通
        if(room.isOnline()){
            ExecutorConstant.ROOM_EXECUTOR.execute(() -> {
                // 如果视频也掉线了，则重连的时候发送消息提示
                List<String> channelUsers = agora.getChannelUsers(room.getRoomId());
                if(channelUsers.contains(userId+"")){
                    return;
                }
                Long callTime = roomService.getCallTime(room);
                RoomWebSocketUtil.sendSendMessage(sessionKey, WsRMsgGen.startVideo(room.getRoomId(), callTime));
                RoomWebSocketUtil.sendSendMessage(sessionKey,WsRMsgGen.sysNotice("重连成功，房间已通话(转换成时分秒) "));
                String sessionKeyReceiver = roomCtxCache.getSessionKeyReceiverByRoomId(room.getRoomId());
                if(StringUtils.isNotEmpty(sessionKeyReceiver)){
                    RoomWebSocketUtil.sendSendMessage(sessionKey,WsRMsgGen.sysNotice("对方已重连成功"));
                }
            });
        }
        if(RoomStatusEnums.STATUS_CREATE.getCode().equals(status) ||
                RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(status) ||
                RoomStatusEnums.STATUS_RECEIVER_CONNECT.getCode().equals(status)){
            // 给当前会话发送消息 - 连线成功
            RoomWebSocketUtil.sendSendMessage(sessionKey, WsRMsgGen.response(room.getRoomId()));
        }
        if(isFirst){
            // 给对方发送呼叫页面 TODO
        }
    }
    public void receiverConnection(String sessionKey,Room room,Long userId){
        Integer status = room.getStatus();
        // 首次链接
        if(RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(status)){
            // 更新缓存
            Map<String,Object> map = new HashMap<>();
            map.put("connectTime", DateUtil.currentSeconds());
            map.put("heartTime",DateUtil.currentSeconds());
            userDataCache.hMSet(room.getRoomId(), UserDataConstant.TYPE_RECEIVER,map);
            boolean res = roomDataCache.setStatusReceiverConnection(room.getRoomId());
            if(!res){
                return;
            }
            userService.updateVideoStatus(userId,1);
            anchorService.updateVideoStatus(userId,1);
        }
        RoomWebSocketUtil.sendSendMessage(sessionKey, WsRMsgGen.response(room.getRoomId()));
        RoomWebSocketUtil.sendSendMessage(sessionKey, WsRMsgGen.updateTip());
    }


}
