package com.wecloud.im.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.mapper.ImConversationMapper;
import com.wecloud.im.mapper.ImConversationMembersMapper;
import com.wecloud.im.param.ApiImConversationMembersInfoPageParam;
import com.wecloud.im.param.ApiImConversationMembersInfoQueryVo;
import com.wecloud.im.param.ApiImConversationMembersPageParam;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.param.ImConvMemeClientRemarkNameParam;
import com.wecloud.im.param.ImConversationMembersListParam;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.param.add.ImConversationMemApiAdd;
import com.wecloud.im.param.add.ImConversationMemAttrUpdate;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImConversationService;
import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.vo.ImConversationMemberListVo;
import com.wecloud.im.ws.enums.MsgTypeEnum;
import com.wecloud.im.ws.enums.WsResponseCmdEnum;
import com.wecloud.im.ws.model.WsResponseModel;
import com.wecloud.im.ws.service.WriteDataService;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.util.SnowflakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 会话成员表 服务实现类
 *
 * @author wei
 * @since 2021-05-07
 */
@Slf4j
@Service
public class ImConversationMembersServiceImpl extends BaseServiceImpl<ImConversationMembersMapper, ImConversationMembers> implements ImConversationMembersService {

    private static final JsonMapper JSON_MAPPER = new JsonMapper();

    @Autowired
    private WriteDataService writeDataService;

    @Autowired
    private ImConversationMapper imConversationMapper;

    @Autowired
    private ImConversationMembersService imConversationMembersService;

    @Autowired
    private ImConversationService imConversationService;

    @Autowired
    private ImClientService imClientService;

    @Autowired
    private ImApplicationService imApplicationService;

    @Autowired
    private ImMessageService imMessageService;

    @Autowired
    private ImConversationMembersMapper imConversationMembersMapper;

    @Override
    public ApiResult<List<ApiImConversationMembersQueryVo>> getRestApiImConversationMembersList(ApiImConversationMembersPageParam apiImConversationMembersPageParam, ImApplication imApplication) {

        List<ApiImConversationMembersQueryVo> restApiImConversationMembersList = imConversationMembersMapper.getRestApiImConversationMembersList(apiImConversationMembersPageParam.getConversationId());
        return ApiResult.ok(restApiImConversationMembersList);
    }

    @Override
    public ApiResult<Paging<ApiImConversationMembersInfoQueryVo>> getApiImConversationMembersInfoList(ApiImConversationMembersInfoPageParam apiImConversationMembersInfoPageParam, ImApplication imApplication) {
        OrderItem orderItem = new OrderItem();
        orderItem.setColumn("im_conversation_members.create_time");
        orderItem.setAsc(false);
        Page<ImConversationMembersQueryVo> page = new PageInfo<>(apiImConversationMembersInfoPageParam, orderItem);

        IPage<ApiImConversationMembersInfoQueryVo> iPage = imConversationMembersMapper.getApiImConversationMembersInfoList(page, apiImConversationMembersInfoPageParam.getConversationId());

        Paging<ApiImConversationMembersInfoQueryVo> paging = new Paging<>(iPage);

        return ApiResult.ok(paging);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> saveOrUpdateClientRemarkName(ImConvMemeClientRemarkNameParam imConvMemeClientRemarkNameParam) {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurentClient();

        // 查询该成员
        ImConversationMembers imConversationMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                        .eq(ImConversationMembers::getFkConversationId, imConvMemeClientRemarkNameParam.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, imClientSender.getId())
        );

        if (imConversationMember == null) {
            return ApiResult.fail();
        }


//        // 查询该会话所有成员
//        List<ImConversationMembers> membersList = imConversationMembersService.list(
//                new QueryWrapper<ImConversationMembers>().lambda()
//                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
//                        .eq(ImConversationMembers::getFkConversationId, imConversationAttrUpdate.getConversationId())
//                        .notIn(ImConversationMembers::getId, imClientSender.getId())
//        );


        imConversationMember.setClientRemarkName(imConvMemeClientRemarkNameParam.getClientRemarkName());


        boolean b = imConversationMembersService.updateById(imConversationMember);
        if (b) {

            //TODO ws下发群成员备注变动事件

            return ApiResult.ok();

        } else {
            return ApiResult.fail();
        }

    }

    @Override
    public List<ImConversationMemberListVo> getImConversationMembersList(ImConversationMembersListParam imConversationMembersListParam) throws Exception {

        return imConversationMembersMapper.getImConversationMembersList(imConversationMembersListParam.getConversationId());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> saveOrUpdateAttr(ImConversationMemAttrUpdate imConversationMemAttrUpdate) {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurentClient();

        // 查询该成员
        ImConversationMembers imConversationMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                        .eq(ImConversationMembers::getFkConversationId, imConversationMemAttrUpdate.getConversationId())
                        .eq(ImConversationMembers::getId, imClientSender.getId())
        );

        if (imConversationMember == null) {
            return ApiResult.fail();
        }


//        // 查询该会话所有成员
//        List<ImConversationMembers> membersList = imConversationMembersService.list(
//                new QueryWrapper<ImConversationMembers>().lambda()
//                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
//                        .eq(ImConversationMembers::getFkConversationId, imConversationAttrUpdate.getConversationId())
//                        .notIn(ImConversationMembers::getId, imClientSender.getId())
//        );

        JsonMapper jsonMapper = new JsonMapper();

        try {
            String attributes = jsonMapper.writeValueAsString(imConversationMemAttrUpdate.getAttributes());

            imConversationMember.setAttributes(attributes);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return ApiResult.fail();
        }

        boolean b = imConversationMembersService.updateById(imConversationMember);
        if (b) {

            //TODO ws下发群成员属性变动事件

            return ApiResult.ok();

        } else {
            return ApiResult.fail();
        }

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveImConversationMembers(ImConversationMembers imConversationMembers) throws Exception {
        return super.save(imConversationMembers);
    }

    @Override
    public boolean addImConversationMembersApi(ImConversationMemApiAdd imConversationMemApiAdd, ImApplication imApplication) {

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())

                        .eq(ImConversationMembers::getFkConversationId, imConversationMemApiAdd.getConversationId())
        );
        if (membersList.isEmpty()) {
            log.info("membersList为空,toConversationId:" + imConversationMemApiAdd.getConversationId());
            return true;
        }

        ImClient operatorClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, imApplication.getId())
                .eq(ImClient::getClientId, imConversationMemApiAdd.getOperator()));

        ImClient passivityOperatorClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, imApplication.getId())
                .eq(ImClient::getClientId, imConversationMemApiAdd.getPassivityOperator()));

        //   判断用户是否已经在该会话
        ImConversationMembers members = imConversationMembersService.getOne(new QueryWrapper<ImConversationMembers>().lambda()
                .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                .eq(ImConversationMembers::getFkConversationId, imConversationMemApiAdd.getConversationId())
                .eq(ImConversationMembers::getFkClientId, passivityOperatorClient.getId())
        );

        // 已经在该会话 则跳过
        if (members != null) {
            return true;
        }

        Long imConversationMembersId2 = SnowflakeUtil.getId();
        ImConversationMembers imConversationMembers2 = new ImConversationMembers();
        imConversationMembers2.setId(imConversationMembersId2);
        imConversationMembers2.setCreateTime(new Date());
        imConversationMembers2.setFkAppid(imApplication.getId());
        imConversationMembers2.setFkConversationId(imConversationMemApiAdd.getConversationId());
        imConversationMembers2.setFkClientId(passivityOperatorClient.getId());
        // 添加到会话
        imConversationMembersService.save(imConversationMembers2);

        // ws邀请事件通知给群内其他人 ----------


        // 生成消息id
        long messageId = SnowflakeUtil.getId();
        ImMessage imMessage = new ImMessage();

        Map<String, Object> content = new HashMap<>();
        content.put("operator", imConversationMemApiAdd.getOperator()); //操作的client ID
        content.put("passivityOperator", imConversationMemApiAdd.getPassivityOperator()); //被操作的client ID
        content.put("joinType", imConversationMemApiAdd.getJoinType()); //被操作的client ID
        content.put("type", MsgTypeEnum.SERVER_INVITE_CLIENT_JOIN_CONVERSATION.getUriCode()); // 服务端api调用 将一名用户添加至会话:   ${clientID}通过${type}加入会话 -1014

        try {
            String contentString = JSON_MAPPER.writeValueAsString(content);
            imMessage.setContent(contentString);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //  保存消息至消息表
        imMessage.setId(messageId);
        imMessage.setCreateTime(new Date());
        imMessage.setFkAppid(imApplication.getId());
        imMessage.setSender(operatorClient.getId());
        imMessage.setWithdraw(false);
        imMessage.setEvent(true);
        imMessage.setSystem(false);
        imMessage.setSendStatus(2);
        imMessage.setFkConversationId(imConversationMemApiAdd.getConversationId());
        boolean save = imMessageService.save(imMessage);

        //推送到被拉入方
        Long fkConversationId = imConversationMemApiAdd.getConversationId();
        String clientId = imConversationMemApiAdd.getOperator();
        String toClientId = passivityOperatorClient.getClientId();
        String imApplicationAppKey = imApplication.getAppKey();
        sendEventMsg(messageId, (HashMap) content, fkConversationId, clientId, toClientId, imApplicationAppKey);


        // 遍历发送
        for (ImConversationMembers conversationMembers : membersList) {

            // 查询接收方
            ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .eq(ImClient::getFkAppid, imApplication.getId())
                    .eq(ImClient::getId, conversationMembers.getFkClientId()));
            if (imClientReceiver == null) {
                continue;
            }

            // 封装响应的实体
            ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

            imMessageOnlineSend.setMsgId(messageId);
            imMessageOnlineSend.setSender("");
            imMessageOnlineSend.setContent((HashMap) content);
            imMessageOnlineSend.setConversationId(conversationMembers.getFkConversationId());
            imMessageOnlineSend.setWithdraw(Boolean.FALSE);
            imMessageOnlineSend.setEvent(Boolean.TRUE);

            //  向接收方推送
            WsResponseModel<ImMessageOnlineSend> responseModel = new WsResponseModel<>();
            responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
            ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
            responseModel.setCode(result.getCode());
            responseModel.setMsg(result.getMessage());
            responseModel.setData(imMessageOnlineSend);
            responseModel.setReqId(null);
            writeDataService.write(responseModel, imApplication.getAppKey(), imClientReceiver.getClientId());

        }

        return true;
    }


    private void sendEventMsg(long messageId, HashMap content, Long fkConversationId, String clientId, String toClientId, String imApplicationAppKey) {
        // 封装响应的实体
        ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();


        imMessageOnlineSend.setMsgId(messageId);
        imMessageOnlineSend.setSender(clientId);
        imMessageOnlineSend.setContent(content);
        imMessageOnlineSend.setConversationId(fkConversationId);
        imMessageOnlineSend.setWithdraw(Boolean.FALSE);
        imMessageOnlineSend.setEvent(Boolean.TRUE);

        //  向接收方推送
        WsResponseModel<ImMessageOnlineSend> responseModel = new WsResponseModel<>();
        responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
        ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
        responseModel.setCode(result.getCode());
        responseModel.setMsg(result.getMessage());
        responseModel.setData(imMessageOnlineSend);
        responseModel.setReqId(null);
        writeDataService.write(responseModel, imApplicationAppKey, toClientId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateImConversationMembers(ImConversationMembers imConversationMembers) throws Exception {
        return super.updateById(imConversationMembers);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteImConversationMembers(Long id) throws Exception {
        return super.removeById(id);
    }

    @Override
    public ImConversationMembersQueryVo getImConversationMembersById(Long id) throws Exception {
        return imConversationMembersMapper.getImConversationMembersById(id);
    }

    @Override
    public Paging<ImConversationMembersQueryVo> getImConversationMembersPageList(ImConversationMembersPageParam imConversationMembersPageParam) throws Exception {
        Page<ImConversationMembersQueryVo> page = new PageInfo<>(imConversationMembersPageParam, OrderItem.desc(getLambdaColumn(ImConversationMembers::getCreateTime)));
        IPage<ImConversationMembersQueryVo> iPage = imConversationMembersMapper.getImConversationMembersPageList(page, imConversationMembersPageParam);
        return new Paging<ImConversationMembersQueryVo>(iPage);
    }

}
