package com.wecloud.im.service.impl;

import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.exception.BusinessException;
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.util.SecurityUtils;
import lombok.extern.slf4j.Slf4j;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
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.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.friend.param.ImFriendApplyParam;
import com.wecloud.im.friend.service.ImFriendService;
import com.wecloud.im.mapper.ImConversationMapper;
import com.wecloud.im.mapper.ImConversationMembersMapper;
import com.wecloud.im.param.ApiImConversationMembersPageParam;
import com.wecloud.im.param.ApiImConversationMembersQueryVo;
import com.wecloud.im.param.ChatSettingParam;
import com.wecloud.im.param.ChatSettingTypeEnum;
import com.wecloud.im.param.ImConvMemeClientRemarkNameParam;
import com.wecloud.im.param.ImConversationMembersPageParam;
import com.wecloud.im.param.ImConversationMembersQueryVo;
import com.wecloud.im.param.ListConversationMembersParam;
import com.wecloud.im.param.SetAdminsParam;
import com.wecloud.im.param.add.ImConversationMemAttrUpdate;
import com.wecloud.im.service.ContextService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImConversationService;
import com.wecloud.im.vo.ConversationMemberVo;
import com.wecloud.im.ws.enums.MsgTypeEnum;
import com.wecloud.im.ws.enums.WsResponseCmdEnum;
import com.wecloud.im.ws.model.WsResponse;
import com.wecloud.im.ws.sender.ChannelSender;
import com.wecloud.utils.JsonUtils;

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

    @Autowired
    private ChannelSender channelSender;

    @Autowired
    private ImConversationMapper imConversationMapper;

    @Autowired
    private ImConversationMembersService imConversationMembersService;

    @Autowired
    private ImConversationService imConversationService;

    @Autowired
    private ImClientService imClientService;

    @Autowired
    private ImConversationMembersMapper imConversationMembersMapper;

    @Autowired
    private ContextService contextService;

    @Autowired
    private ImFriendService imFriendService;

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateClientRemarkName(ImConvMemeClientRemarkNameParam param) {
        ImClient currentClient = imClientService.getCurrentClient();
        // 查询该成员
        ImConversationMembers imConversationMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, currentClient.getFkAppid())
                        .eq(ImConversationMembers::getFkConversationId, param.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, currentClient.getId())
        );
        if (imConversationMember == null) {
            throw new BusinessException("未查询到会话成员信息");
        }
        imConversationMember.setClientRemarkName(param.getClientRemarkName());
        boolean b = imConversationMembersService.updateById(imConversationMember);
        if (!b) {
            throw new BusinessException("修改群成员备注失败");
        }
        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, currentClient.getFkAppid())
                        .eq(ImConversationMembers::getFkConversationId, param.getConversationId())
                        .ne(ImConversationMembers::getFkClientId, currentClient.getId())
        );
        for (ImConversationMembers member : membersList) {
            // 不关心事件是否发送成功
            try {
                // 给所有成员下发事件消息
                ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, currentClient.getFkAppid())
                        .eq(ImClient::getId, member.getFkClientId()));
                if (imClientReceiver == null) {
                    continue;
                }

                // 封装响应的实体
                ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();
                imMessageOnlineSend.setCreateTime(new Date());
                imMessageOnlineSend.setType(MsgTypeEnum.CONVERSATION_MEMBER_NAME_MODIFY.getUriCode());
                imMessageOnlineSend.setSender(currentClient.getClientId());
                Map<String, Object> content = Maps.newHashMap();
                content.put("operator", currentClient.getClientId());
                content.put("remarkName", param.getClientRemarkName());
                imMessageOnlineSend.setContent(content);
                imMessageOnlineSend.setConversationId(param.getConversationId());
                imMessageOnlineSend.setWithdraw(Boolean.FALSE);
                imMessageOnlineSend.setEvent(Boolean.TRUE);

                //  向接收方推送
                WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
                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);
                channelSender.sendMsg(responseModel, imClientReceiver.getId());
            } catch (Exception e) {
                log.info("下发解散群事件失败，接收人 {}", JSON.toJSONString(member));
            }
        }
    }

    @Override
    public List<ConversationMemberVo> getImConversationMembersList(ListConversationMembersParam param) {
        return imConversationMembersMapper.getImConversationMembersList(param);
    }

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

        // 获取当前client
        ImClient createClient = contextService.getImClientIfNotNullOrThrow();
        //  根据appId查询application
        ImApplication imApplication = contextService.getImApplicationIfNotNullOrThrow(createClient.getFkAppid());

        ImClient imClientSender = imClientService.getCurrentClient();

        // 查询该成员
        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 false;
        }


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

        String attributes = JsonUtils.encodeJson(imConversationMemAttrUpdate.getAttributes());
        imConversationMember.setAttributes(attributes);


        boolean b = imConversationMembersService.updateById(imConversationMember);
        //TODO ws下发群成员属性变动事件
        return b;

    }


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

    @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) {
        return super.removeById(id);
    }

    @Override
    public void deleteByConversationId(Long conversationId) {
        imConversationMembersMapper.deleteByConversationId(conversationId);
    }

    @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);
    }

    @Override
    public List<Long> findThousandGroupsByClientId(Long clientId) {
        return imConversationMembersMapper.findThousandGroupsByClientId(clientId);
    }

    /**
     * 批量设置群成员
     * @param param
     * @param fkClientIds
     */
    @Override
    public void setAdminsForConversation(SetAdminsParam param, List<Long> fkClientIds) {
        Integer role = param.getOperateType() == 1 ? 2 : 1;
        imConversationMembersMapper.setAdminsForConversation(param.getConversationId(), fkClientIds, role);
    }

    @Override
    public Boolean chatSetting(ChatSettingParam param) {
        Long appId = SecurityUtils.getCurrentAppId();
        String clientId = param.getClientId();
        Long conversationId = param.getConversationId();
        ChatSettingTypeEnum type = param.getType();
        Boolean on = param.getOn();

        // 找到对应的会话
        ImConversationMembers conversation =
                baseMapper.selectOne(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getClientId, clientId)
                        .eq(ImConversationMembers::getFkConversationId, conversationId)
                        .eq(ImConversationMembers::getFkAppid, appId));
        if (conversation == null) {
            throw new BusinessException("会话不存在");
        }
        boolean result = false;
        if (ChatSettingTypeEnum.TOP.equals(type)) {
            result = update(Wrappers.<ImConversationMembers>lambdaUpdate().eq(ImConversationMembers::getId,
                    conversation.getId()).set(ImConversationMembers::getTop, on));

        } else if (ChatSettingTypeEnum.DO_NOT_DISTURB.equals(type)) {
            result = update(Wrappers.<ImConversationMembers>lambdaUpdate().eq(ImConversationMembers::getId,
                    conversation.getId()).set(ImConversationMembers::getDoNotDisturb, on));
        }
        return result;
    }

    @Override
    public Boolean addUser(ImFriendApplyParam param) {
        Long appId = SecurityUtils.getCurrentAppId();
        Long conversationId = param.getConversationId();
        // 判断会话是否存在
        ImConversation conversation = imConversationService.getById(conversationId);
        if (conversation == null) {
            throw new BusinessException("会话不存在");
        }
        // 判断会话是否开启禁止群成员互加好友
        boolean forbidAddFriend = conversation.getForbidAddFriend();
        if (forbidAddFriend) {
            throw new BusinessException("群主/管理员开启了禁止群成员互加好友");
        }
        // 判断是否同一个会话成员
        List<String> memberClientIds = new ArrayList<>();
        memberClientIds.add(param.getClientId());
        memberClientIds.add(param.getFriendClientId());
        List<ImConversationMembers> members =
                list(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getFkAppid, appId)
                        .eq(ImConversationMembers::getFkConversationId, conversationId)
                        .in(ImConversationMembers::getClientId, memberClientIds));
        if (members.size() != 2) {
            throw new BusinessException("好友不属于同一个群");
        }
        // 校验通过，调用imFriendService apply方法
        ImClient initiator = imClientService.getCacheImClient(appId, param.getClientId());
        ImClient recipient = imClientService.getCacheImClient(appId, param.getFriendClientId());

        return imFriendService.applyFriend(initiator, recipient, param.getFriendName(),
                param.getRequestRemark());
    }
}
