package com.wecloud.rtc.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.param.rtc.CandidateForwardParam;
import com.wecloud.im.param.rtc.CreateRtcChannelParam;
import com.wecloud.im.param.rtc.CreateRtcChannelResult;
import com.wecloud.im.param.rtc.JoinRtcChannelParam;
import com.wecloud.im.param.rtc.LeaveRtcChannelParam;
import com.wecloud.im.param.rtc.RejectRtcChannelParam;
import com.wecloud.im.param.rtc.SdpForwardParam;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientBlacklistService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.ws.cache.UserStateCacheManager;
import com.wecloud.im.ws.cache.UserStateListener;
import com.wecloud.rtc.entity.response.RtcCallResponse;
import com.wecloud.rtc.entity.response.RtcCandidateForwardResponse;
import com.wecloud.rtc.entity.response.RtcClientJoinResponse;
import com.wecloud.rtc.entity.response.RtcClientLeaveResponse;
import com.wecloud.rtc.entity.response.RtcClientRejectResponse;
import com.wecloud.rtc.entity.response.RtcSdpForwardResponse;
import com.wecloud.rtc.service.MangerRtcCacheService;
import com.wecloud.rtc.service.RtcService;
import com.wecloud.rtc.service.WsRtcWrite;
import com.wecloud.utils.SnowflakeUtil;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class RtcServiceImpl extends UserStateListener implements RtcService {

    @Autowired
    private ImApplicationService imApplicationService;

    @Autowired
    private WsRtcWrite wsRtcWrite;

    /**
     * redis缓存
     */
    @Autowired
    private MangerRtcCacheService mangerRtcCacheService;

    @Autowired
    private ImClientService imClientService;

    @Autowired
    private UserStateCacheManager userStateCacheManager;

    @Autowired
    private ImClientBlacklistService imClientBlacklistService;

    @Override
    public void onLineEvent(Long client, Integer platform, String longChannelId) {
        // nothing need to do
    }

    @Override
    public void offlineEvent(Long clientId, Integer platform, String longChannelId) {
        //  根据appKey查询appid
        ImClient client = imClientService.getCacheImClient(clientId);

        // 获取该客户端加入的频道ID
        Long listByClientId = mangerRtcCacheService.getRtcChannelIdListByClientId(client.getId());
        if (listByClientId == null) {
            return;
        }

        LeaveRtcChannelParam leaveRtcChannelParam = new LeaveRtcChannelParam();
        leaveRtcChannelParam.setChannelId(listByClientId);
        // websocket离线逻辑  服务端踢出频道
        this.leave(leaveRtcChannelParam);
    }

    @Override
    public ApiResult<CreateRtcChannelResult> createAndCall(CreateRtcChannelParam createRtcChannelParam) {
        ImClient currentClient = imClientService.getCurrentClient();
        Long rtcChannelId = SnowflakeUtil.getId();
        //  判断发起方必须在线
        boolean onlineStatus = userStateCacheManager.isOnline(currentClient.getId());
        if (!onlineStatus) {
            log.info("发起方必须在线" + currentClient.getFkAppid() + currentClient.getClientId());
            ApiResult.fail();
        }
        ImClient toClient = imClientService.getCacheImClient(currentClient.getFkAppid(), createRtcChannelParam.getToClient());
        if (toClient == null) {
            ApiResult.fail();
        }
        // 拉黑逻辑
        black(currentClient, toClient);
        // 添加缓存
        mangerRtcCacheService.create(currentClient.getId(), toClient.getId(), rtcChannelId);

        CreateRtcChannelResult createRtcChannelResult = new CreateRtcChannelResult();
        createRtcChannelResult.setChannelId(rtcChannelId);

        // ws向接收方发送通知
        RtcCallResponse rtcCallResponse = new RtcCallResponse();
        rtcCallResponse.setCallType(createRtcChannelParam.getCallType());
        rtcCallResponse.setConversationId(createRtcChannelParam.getConversationId());
        rtcCallResponse.setChannelId(rtcChannelId);
        rtcCallResponse.setClientId(currentClient.getClientId());
        rtcCallResponse.setTimestamp(System.currentTimeMillis());

        wsRtcWrite.rtcCall(rtcCallResponse, toClient.getId());

        // TODO 待开发 下发安卓和ios系统推送

        return ApiResult.ok(createRtcChannelResult);


    }

    @Override
    public ApiResult<Boolean> join(JoinRtcChannelParam joinRtcChannelParam) {

        ImClient client = imClientService.getCurrentClient();

        // 修改缓存
        mangerRtcCacheService.join(client.getId(), joinRtcChannelParam.getChannelId());

        //获取频道内所有client
        List<String> clientListByRtcChannelId = mangerRtcCacheService.getClientListByRtcChannelId(joinRtcChannelParam.getChannelId());
        // 移除自己
        clientListByRtcChannelId.remove(client.getId().toString());

        for (String toClientId : clientListByRtcChannelId) {

            // ws向接收方发送通知
            RtcClientJoinResponse rtcSdpForwardResponse = new RtcClientJoinResponse();

            rtcSdpForwardResponse.setChannelId(joinRtcChannelParam.getChannelId());
            rtcSdpForwardResponse.setClientId(client.getClientId());
            rtcSdpForwardResponse.setTimestamp(System.currentTimeMillis());
            wsRtcWrite.clientJoin(rtcSdpForwardResponse, Long.valueOf(toClientId));
        }

        return ApiResult.ok(true);
    }

    @Override
    public ApiResult<Boolean> reject(RejectRtcChannelParam rejectRtcChannelParam) {
        ImClient client = imClientService.getCurrentClient();
        // 修改缓存
        mangerRtcCacheService.leave(client.getId(), rejectRtcChannelParam.getChannelId());
        //获取频道内所有client
        List<String> clientListByRtcChannelId = mangerRtcCacheService.getClientListByRtcChannelId(rejectRtcChannelParam.getChannelId());

        for (String toClientId : clientListByRtcChannelId) {
            // ws向接收方发送通知
            RtcClientRejectResponse rtcClientRejectResponse = new RtcClientRejectResponse();

            rtcClientRejectResponse.setChannelId(rejectRtcChannelParam.getChannelId());
            rtcClientRejectResponse.setClientId(client.getClientId());
            rtcClientRejectResponse.setTimestamp(System.currentTimeMillis());
            wsRtcWrite.clientReject(rtcClientRejectResponse, Long.valueOf(toClientId));
        }

        // 判断频道内是否无其他人了
        if (CollectionUtils.isEmpty(clientListByRtcChannelId)) {
            // 移除频道信息
            mangerRtcCacheService.delChannelInfo(rejectRtcChannelParam.getChannelId());
        } else if (clientListByRtcChannelId.size() == 1){
            // 频道内只有一个人了 -- 删除频道 并将这个人设为离开
            mangerRtcCacheService.leave(Long.valueOf(clientListByRtcChannelId.get(0)), rejectRtcChannelParam.getChannelId());
            mangerRtcCacheService.delChannelInfo(rejectRtcChannelParam.getChannelId());
        }
        return ApiResult.ok(true);
    }

    @Override
    public ApiResult<Boolean> leave(LeaveRtcChannelParam leaveRtcChannelParam) {
        ImClient currentClient = imClientService.getCurrentClient();
        this.leave(leaveRtcChannelParam, currentClient);

        return ApiResult.ok(true);
    }

    private void leave(LeaveRtcChannelParam leaveRtcChannelParam, ImClient currentClient) {
        // 修改缓存
        mangerRtcCacheService.leave(currentClient.getId(), leaveRtcChannelParam.getChannelId());

        //获取频道内所有client
        List<String> clientListByRtcChannelId = mangerRtcCacheService.getClientListByRtcChannelId(leaveRtcChannelParam.getChannelId());

        for (String toClientId : clientListByRtcChannelId) {
            // ws向接收方发送通知
            RtcClientLeaveResponse rtcClientLeaveResponse = new RtcClientLeaveResponse();

            rtcClientLeaveResponse.setChannelId(leaveRtcChannelParam.getChannelId());
            rtcClientLeaveResponse.setClientId(currentClient.getClientId());
            rtcClientLeaveResponse.setTimestamp(System.currentTimeMillis());
            wsRtcWrite.clientLeave(rtcClientLeaveResponse, Long.valueOf(toClientId));
        }

        // 判断频道内是否无其他人了
        if (CollectionUtils.isEmpty(clientListByRtcChannelId)) {
            // 移除频道信息
            mangerRtcCacheService.delChannelInfo(leaveRtcChannelParam.getChannelId());
        } else if (clientListByRtcChannelId.size() == 1){
            // 频道内只有一个人了 -- 删除频道 并将这个人设为离开
            mangerRtcCacheService.leave(Long.valueOf(clientListByRtcChannelId.get(0)), leaveRtcChannelParam.getChannelId());
            mangerRtcCacheService.delChannelInfo(leaveRtcChannelParam.getChannelId());
        }
    }

    @Override
    public ApiResult<Boolean> sdpForward(SdpForwardParam sdpForwardParam) {

        ImClient client = imClientService.getCurrentClient();
        Long rtcChannelId = SnowflakeUtil.getId();

        //  根据appKey查询appid
        ImApplication imApplication = imApplicationService.getCacheById(client.getFkAppid());

        //  判断发起方必须在线
        boolean onlineStatus = userStateCacheManager.isOnline(client.getId());
        if (!onlineStatus) {
            log.info("发起方必须在线" + imApplication.getAppKey() + client.getClientId());
            ApiResult.fail();
        }

        CreateRtcChannelResult createRtcChannelResult = new CreateRtcChannelResult();
        createRtcChannelResult.setChannelId(rtcChannelId);

        //获取频道内所有client
        List<String> clientListByRtcChannelId = mangerRtcCacheService.getClientListByRtcChannelId(sdpForwardParam.getChannelId());
        // 移除自己
        clientListByRtcChannelId.remove(client.getId().toString());

        for (String toClientId : clientListByRtcChannelId) {

            // ws向接收方发送通知
            RtcSdpForwardResponse rtcSdpForwardResponse = new RtcSdpForwardResponse();
            rtcSdpForwardResponse.setSdpData(sdpForwardParam.getSdpData());
            rtcSdpForwardResponse.setSdpType(sdpForwardParam.getSdpType());

            rtcSdpForwardResponse.setChannelId(rtcChannelId);
            rtcSdpForwardResponse.setClientId(client.getClientId());
            rtcSdpForwardResponse.setTimestamp(System.currentTimeMillis());
            wsRtcWrite.sdpForward(rtcSdpForwardResponse, Long.valueOf(toClientId));
        }


        return ApiResult.ok(true);
    }

    @Override
    public ApiResult<Boolean> candidateForward(CandidateForwardParam candidateForwardParam) {

        ImClient client = imClientService.getCurrentClient();
        Long rtcChannelId = SnowflakeUtil.getId();

        //  根据appKey查询appid
        ImApplication imApplication = imApplicationService.getCacheById(client.getFkAppid());

        //  判断发起方必须在线
        boolean onlineStatus = userStateCacheManager.isOnline(client.getId());
        if (!onlineStatus) {
            log.info("发起方必须在线" + imApplication.getAppKey() + client.getClientId());
            ApiResult.fail();
        }

        CreateRtcChannelResult createRtcChannelResult = new CreateRtcChannelResult();
        createRtcChannelResult.setChannelId(rtcChannelId);

        //获取频道内所有client
        List<String> clientListByRtcChannelId = mangerRtcCacheService.getClientListByRtcChannelId(candidateForwardParam.getChannelId());
        // 移除自己
        clientListByRtcChannelId.remove(client.getId().toString());

        for (String toClientId : clientListByRtcChannelId) {

            // ws向接收方发送通知
            RtcCandidateForwardResponse rtcCandidateForwardResponse = new RtcCandidateForwardResponse();

            rtcCandidateForwardResponse.setCandidateData(candidateForwardParam.getCandidateData());

            rtcCandidateForwardResponse.setChannelId(rtcChannelId);
            rtcCandidateForwardResponse.setClientId(client.getClientId());
            rtcCandidateForwardResponse.setTimestamp(System.currentTimeMillis());
            wsRtcWrite.candidateForward(rtcCandidateForwardResponse, Long.valueOf(toClientId));
        }

        return ApiResult.ok(true);
    }


    /**
     * 判断是否被拉黑
     *
     * @param currentClient
     * @param toClient
     * @return
     */
    private void black(ImClient currentClient, ImClient toClient) {
        // 判断是否被拉黑
        boolean beBlack = imClientBlacklistService.isBeBlack(toClient.getClientId(), currentClient.getClientId());
        if (beBlack) {
            throw new BusinessException("被对方拉黑了");
        }
        // 是否把对方拉黑
        boolean black = imClientBlacklistService.isBeBlack(currentClient.getClientId(), toClient.getClientId());
        if (black) {
            throw new BusinessException("你把对方拉黑了");
        }
    }
}
