package com.wecloud.im.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImClientBlacklist;
import com.wecloud.im.enums.FriendStateEnum;
import com.wecloud.im.enums.RelationEnum;
import com.wecloud.im.friend.entity.ImFriend;
import com.wecloud.im.friend.service.ImFriendService;
import com.wecloud.im.mapper.ImClientMapper;
import com.wecloud.im.param.ClientInfoParam;
import com.wecloud.im.param.GetClientInfoParam;
import com.wecloud.im.param.ImClientPageParam;
import com.wecloud.im.param.ImClientQueryVo;
import com.wecloud.im.param.ImClientSimpleDto;
import com.wecloud.im.param.add.ImClientDeviceInfoAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAdd;
import com.wecloud.im.param.add.ImClientHeadPortraitAndNicknameUpdate;
import com.wecloud.im.param.add.ImClientNicknameAdd;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientBlacklistService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.vo.ClientInfoVo;
import com.wecloud.im.vo.GetInfoListVo;
import com.wecloud.im.vo.MyInfoVo;
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.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * 终端表 服务实现类
 *
 * @author wei
 * @since 2021-04-27
 */
@Slf4j
@Service
@CacheConfig(cacheNames = "client")
public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClient> implements ImClientService {

    @Autowired
    private ImClientMapper imClientMapper;
    @Autowired
    private ImApplicationService imApplicationService;

    @Autowired
    private ImFriendService imFriendService;

    @Autowired
    private ImClientBlacklistService imClientBlacklistService;


    @Override
    public MyInfoVo getMyInfo() {
        ImClient currentClient = this.getCurentClient();
        if (currentClient == null) {
            throw new BusinessException("当前用户登录信息失效");
        }
        MyInfoVo myInfoVo = new MyInfoVo();
        BeanUtils.copyProperties(currentClient, myInfoVo);
        return myInfoVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateHeadPortrait(ImClientHeadPortraitAdd imClientHeadPortraitAdd) throws Exception {
        ImClient curentClient = getCurentClient();

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


        curentClient.setHeadPortrait(imClientHeadPortraitAdd.getHeadPortrait());
        imClientMapper.updateById(curentClient);

        // 清除client的redis缓存
        deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());

        return true;
    }

    @Override
    public boolean updateHeadAndNickname(ImClientHeadPortraitAndNicknameUpdate imClientHeadPortraitAndNicknameUpdate) {
        ImClient curentClient = getCurentClient();

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


        curentClient.setHeadPortrait(imClientHeadPortraitAndNicknameUpdate.getHeadPortrait());
        curentClient.setNickname(imClientHeadPortraitAndNicknameUpdate.getNickname());
        imClientMapper.updateById(curentClient);

        // 清除client的redis缓存
        deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());

        return true;
    }

    @Override
    public ApiResult<List<GetInfoListVo>> getInfoList(GetClientInfoParam getClientInfoParam) throws Exception {
        ImClient curentClient = getCurentClient();

        if (getClientInfoParam.getClientIds() == null || getClientInfoParam.getClientIds().isEmpty()) {
            throw new BusinessException("getClientInfoParam.getClientIds() == null");
        }

//        List<ImClient> imClients = this.list(new QueryWrapper<ImClient>().lambda()
//                .eq(ImClient::getFkAppid, curentClient.getFkAppid())
//                .in(ImClient::getClientId, getClientInfoParam.getClientId())
//        );
//
//        List<GetInfoListVo> getInfoListVos = new ArrayList<>();
//
//        for (ImClient imClient : imClients) {
//
//            GetInfoListVo getInfoListVo = new GetInfoListVo();
//            getInfoListVo.setHeadPortrait(imClient.getHeadPortrait());
//            getInfoListVo.setNickname(imClient.getNickname());
//            getInfoListVo.setClientId(imClient.getClientId());
//            getInfoListVos.add(getInfoListVo);
//        }

        List<GetInfoListVo> infoList = imClientMapper.getInfoList(curentClient.getFkAppid(), getClientInfoParam.getConversationId(), getClientInfoParam.getClientIds());

        return ApiResult.ok(infoList);
    }

    @Override
    public ClientInfoVo getClientInfo(ClientInfoParam param) {
        ImClient currentClient = this.getCurentClient();
        if (currentClient == null) {
            throw new BusinessException("当前用户登录信息失效");
        }
        List<GetInfoListVo> infoList = imClientMapper.getInfoList(currentClient.getFkAppid(), param.getConversationId(),
                Lists.newArrayList(param.getClientId()));
        if (CollectionUtils.isEmpty(infoList)) {
            throw new BusinessException("群内未查询到该用户信息");
        }
        ClientInfoVo clientInfoVo = new ClientInfoVo();
        BeanUtils.copyProperties(infoList.get(0), clientInfoVo);
        clientInfoVo.setRelation(RelationEnum.STRANGER.getCode());
        // 查询该好友与自己关系： 陌生人、好友、被拉黑名单
        ImFriend imFriend = imFriendService.getByKey(currentClient.getId(), clientInfoVo.getId());
        if (imFriend != null && FriendStateEnum.CONFORM.getCode().equals(imFriend.getState())) {
            clientInfoVo.setRelation(RelationEnum.FRIEND.getCode());
        }
        // 查询是否被拉黑
        if (imClientBlacklistService.isBeBlack(currentClient.getId(), clientInfoVo.getId())) {
            clientInfoVo.setRelation(RelationEnum.BE_BLACK.getCode());
        }
        return clientInfoVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNickname(ImClientNicknameAdd imClientNicknameAdd) throws Exception {
        ImClient curentClient = getCurentClient();

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


        curentClient.setNickname(imClientNicknameAdd.getNickname());
        imClientMapper.updateById(curentClient);

        // 清除client的redis缓存
        deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveImClient(ImClient imClient) throws Exception {
        return super.save(imClient);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDeviceInfo(ImClientDeviceInfoAdd imClientDevice) {

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

        // 清除旧client的redis缓存
        ImClient imClient = this.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, imApplication.getId())
                .eq(ImClient::getDeviceToken, imClientDevice.getDeviceToken()));
        if (imClient != null) {
            deleteCacheImClient(imClient.getFkAppid(), imClient.getClientId());
            // client登陆的时候 判断数据库内是否已经存在这个设备token,如果存在就清空旧的
            this.removeOldToken(imApplication.getId(), curentJwtToken.getToken());
        }

        ImClient client = getCurentClient();
        ImClient clientNew = new ImClient();
        BeanUtils.copyProperties(imClientDevice, clientNew);
        clientNew.setId(client.getId());

        // 清除新client的redis缓存
        deleteCacheImClient(client.getFkAppid(), client.getClientId());

        // 修改
        return this.updateImClient(clientNew);
    }

    @Override
    public boolean logout() {

        ImClient curentClient = getCurentClient();

        // 清除设备token
        boolean update = this.update(new UpdateWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, curentClient.getFkAppid())
                .eq(ImClient::getId, curentClient.getId())
                .set(ImClient::getDeviceToken, null)
        );
        if (update) {
            // 清除新client的redis缓存
            deleteCacheImClient(curentClient.getFkAppid(), curentClient.getClientId());
        }

        return update;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateImClient(ImClient imClient) {
        return super.updateById(imClient);
    }

    @Override
    public boolean deleteImClient(Long id) throws Exception {
        return super.removeById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int removeOldToken(Long appId, String deviceToken) {

        return imClientMapper.removeOldToken(appId, deviceToken);
    }

    @Override
    public Paging<ImClientQueryVo> getImClientPageList(ImClientPageParam imClientPageParam) throws Exception {
        Page<ImClientQueryVo> page = new PageInfo<>(imClientPageParam, OrderItem.desc(getLambdaColumn(ImClient::getCreateTime)));
        IPage<ImClientQueryVo> iPage = imClientMapper.getImClientPageList(page, imClientPageParam);
        return new Paging<>(iPage);
    }

    @Override
    public ImClient getCurentClient() {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
        //  根据appKey查询appid
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());
        return getCacheImClient(imApplication.getId(), curentJwtToken.getClientId());
    }

    @Override
    @Cacheable(key = "#p0+#p1")
    public ImClient getCacheImClient(Long applicationId, String clientId) {
        return this.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, applicationId)
                .eq(ImClient::getClientId, clientId));
    }

    @Override
    @CacheEvict(key = "#p0+#p1")
    public void deleteCacheImClient(Long applicationId, String clientId) {
    }

    @Override
//    @Cacheable(key = "#p0")
    public ImClient getCacheImClient(Long id) {
        return imClientMapper.selectById(id);
    }

    @Override
    public List<ImClientSimpleDto> getSimpleClients(Long applicationId, List<String> clientId) {
        return imClientMapper.getSimpleClients(applicationId, clientId);
    }

    @Override
    public List<ImClientSimpleDto> getSimpleClients(List<Long> ids) {
        return imClientMapper.getSimpleClientsByIds(ids);
    }

}
