package com.tzld.piaoquan.api.job.wecom.thirdpart;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.tzld.piaoquan.api.component.WeComThirdPartyApiClient;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ThirdPartWeComRoomMapper;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ThirdPartWeComRoomUserMapper;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ThirdPartWeComStaffMapper;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ThirdPartWeComStaffUserMapper;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ext.ThirdPartWeComMapperExt;
import com.tzld.piaoquan.api.dao.mapper.wecom.thirdpart.ext.ThirdPartWeComRoomMapperExt;
import com.tzld.piaoquan.api.model.param.wecom.thirdpart.*;
import com.tzld.piaoquan.api.model.po.wecom.thirdpart.*;
import com.tzld.piaoquan.api.model.vo.wecom.thirdpart.ThirdPartyAccountConfigVO;
import com.tzld.piaoquan.api.service.wecom.thirdparty.WeComThirdPartyAccountService;
import com.tzld.piaoquan.api.service.wecom.thirdparty.WeComThirdPartyRoomService;
import com.tzld.piaoquan.api.service.wecom.thirdparty.WeComThirdPartyService;
import com.tzld.piaoquan.growth.common.utils.RedisUtils;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class WeComUserDetailJob {

    @Autowired
    WeComThirdPartyService thirdPartyService;
    @Autowired
    WeComThirdPartyAccountService thirdPartyAccountService;
    @Autowired
    WeComThirdPartyRoomService thirdPartyRoomService;
    @Autowired
    WeComThirdPartyApiClient apiClient;
    @Autowired
    ThirdPartWeComStaffMapper staffMapper;
    @Autowired
    ThirdPartWeComRoomMapper roomMapper;
    @Autowired
    ThirdPartWeComStaffUserMapper staffUserMapper;
    @Autowired
    ThirdPartWeComRoomUserMapper roomUserMapper;
    @Autowired
    ThirdPartWeComMapperExt thirdPartWeComMapperExt;
    @Autowired
    ThirdPartWeComRoomMapperExt thirdPartWeComRoomMapperExt;

    @Autowired
    private RedisUtils redisUtils;

    @Value("${create.room.send.msg.status.nums:20}")
    private Integer sendMsgStatusNums;

    @Value("${create.room.member.max.nums:40}")
    private Integer memberMaxNums;

    @Value("${create.room.auto.send.msg:false}")
    private Boolean autoSendMsg;

    private final static ExecutorService pool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10000),
            new ThreadFactoryBuilder().setNameFormat("SyncUserDetailJob-%d").build(),
            new ThreadPoolExecutor.AbortPolicy());

    @XxlJob("syncUserDetail")
    public ReturnT<String> syncUserDetail(String param) {
        List<ThirdPartWeComStaff> activeStaffList = thirdPartyService.getActiveStaffList();
        CountDownLatch cdl = new CountDownLatch(activeStaffList.size());
        for (ThirdPartWeComStaff staff : activeStaffList) {
            pool.execute(() -> {
                try {
                    syncStaffUserDetail(staff);
                } catch (Exception e) {
                    log.error("syncUserDetail error", e);
                } finally {
                    cdl.countDown();
                }
            });
        }
        try {
            cdl.await();
        } catch (InterruptedException e) {
            log.error("syncUserDetail error", e);
        }
        return ReturnT.SUCCESS;
    }

    public void syncStaffUserDetail(ThirdPartWeComStaff staff) {
        // redis锁
        String lockKey = "wecom:thirdpart:userDetail:lock:" + staff.getThirdUuid();
        if (!redisUtils.tryLock(lockKey, "1", 5 * 60)) {
            return;
        }
        String uuid = staff.getThirdUuid();
        String offLineKey = "wecom:thirdpart:offline:" + uuid;
        if (redisUtils.containsKey(offLineKey)) {
            return;
        }
        String response = apiClient.getRunClientByUuid(new UuidRequest(uuid));
        CommonResponse<LoginInfo> commonResponse =
                JSONObject.parseObject(response, new TypeReference<CommonResponse<LoginInfo>>() {
                });
        if (commonResponse.getErrcode() == 0) {
            LoginInfo loginInfo = commonResponse.getData();
            staff.setName(loginInfo.getUser_info().getObject().getNickname());
            staff.setRealName(loginInfo.getUser_info().getObject().getRealname());
            staff.setMobile(loginInfo.getUser_info().getObject().getMobile());
            staff.setAvatar(loginInfo.getUser_info().getObject().getAvatar());
            staff.setName(loginInfo.getUser_info().getObject().getNickname());
            staff.setUpdateTime(new Date());
            staffMapper.updateByPrimaryKeySelective(staff);
        }
        syncRoomList(staff);
        syncStaffUserList(staff);
        // 清除redis锁
        redisUtils.del(lockKey);
    }

    private void syncStaffUserList(ThirdPartWeComStaff staff) {
        List<ExternalContactsResponse.ContactItem> contactItemList = thirdPartyService.getExternalContacts(
                new GetExternalContactsRequest(staff.getThirdUuid(), 100, 0));
        if (CollectionUtils.isEmpty(contactItemList)) {
            return;
        }
        Long thirdStaffId = staff.getThirdStaffId();
        List<ThirdPartWeComStaffUser> existUserList = getThirdPartWeComStaffUserListByStaffId(thirdStaffId);
        List<Long> existUserIdList = existUserList.stream().map(ThirdPartWeComStaffUser::getUserId).collect(Collectors.toList());
        Map<Long, ThirdPartWeComStaffUser> existUserMap = existUserList.stream()
                .collect(Collectors.toMap(ThirdPartWeComStaffUser::getUserId, user -> user, (a, b) -> {
                    if (a.getAddCustomerTime() == 0) {
                        return b;
                    } else if (b.getAddCustomerTime() == 0) {
                        return a;
                    } else if (a.getAddCustomerTime() > b.getAddCustomerTime()) {
                        return b;
                    }
                    return b;
                }));
        List<ThirdPartWeComStaffUser> saveList = new ArrayList<>();
        List<ThirdPartWeComStaffUser> updateList = new ArrayList<>();
        for (ExternalContactsResponse.ContactItem contactItem : contactItemList) {
            if (existUserIdList.contains(contactItem.getUser_id())) {
                //0 互相删除 8主动删除拉黑  2049被删除  其他的都是好友
                List<Integer> deleteStatusList = Arrays.asList(0, 8, 2049);
                ThirdPartWeComStaffUser existUser = existUserMap.get(contactItem.getUser_id());
                existUser.setUpdateTime(new Date());
                if (Objects.isNull(existUser.getRemoveCustomerTime()) && deleteStatusList.contains(contactItem.getStatus())) {
                    if (!deleteStatusList.contains(existUser.getStatus())) {
                        existUser.setRemoveCustomerTime(System.currentTimeMillis() / 1000);
                    } else {
                        // 历史已删除，设为前一天
                        existUser.setRemoveCustomerTime((System.currentTimeMillis() / 1000) - 86400);
                    }
                }
                existUser.setAddCustomerTime(contactItem.getAdd_customer_time());
                existUser.setUnionid(contactItem.getUnionid());
                existUser.setSex(contactItem.getSex());
                existUser.setMobile(contactItem.getMobile());
                existUser.setCompanyRemark(contactItem.getCompany_remark());
                existUser.setAcctid(contactItem.getAcctid());
                existUser.setAvatar(contactItem.getAvatar());
                existUser.setSource(contactItem.getSource());
                existUser.setEnglishName(contactItem.getEnglish_name());
                existUser.setRemarkPhone(JSONObject.toJSONString(contactItem.getRemark_phone()));
                existUser.setRealname(contactItem.getRealname());
                existUser.setRealRemarks(contactItem.getReal_remarks());
                existUser.setLabelid(JSONObject.toJSONString(contactItem.getLabelid()));
                existUser.setUserId(contactItem.getUser_id());
                existUser.setNickname(contactItem.getNickname());
                existUser.setPosition(contactItem.getPosition());
                existUser.setCorpId(contactItem.getCorp_id());
                existUser.setSeq(contactItem.getSeq());
                existUser.setStatus(contactItem.getStatus());

                //staffUserMapper.updateByPrimaryKeySelective(existUser);
                updateList.add(existUser);
            } else {
                ThirdPartWeComStaffUser staffUser = new ThirdPartWeComStaffUser();
                staffUser.setThirdStaffId(thirdStaffId);
                staffUser.setCreateTime(new Date());
                staffUser.setUpdateTime(new Date());

                // 从ContactItem对象复制所有字段值
                staffUser.setAddCustomerTime(contactItem.getAdd_customer_time());
                staffUser.setUnionid(contactItem.getUnionid());
                staffUser.setSex(contactItem.getSex());
                staffUser.setMobile(contactItem.getMobile());
                staffUser.setCompanyRemark(contactItem.getCompany_remark());
                staffUser.setAcctid(contactItem.getAcctid());
                staffUser.setAvatar(contactItem.getAvatar());
                staffUser.setSource(contactItem.getSource());
                staffUser.setEnglishName(contactItem.getEnglish_name());
                staffUser.setRemarkPhone(JSONObject.toJSONString(contactItem.getRemark_phone()));
                staffUser.setRealname(contactItem.getRealname());
                staffUser.setRealRemarks(contactItem.getReal_remarks());
                staffUser.setLabelid(JSONObject.toJSONString(contactItem.getLabelid()));
                staffUser.setUserId(contactItem.getUser_id());
                staffUser.setNickname(contactItem.getNickname());
                staffUser.setPosition(contactItem.getPosition());
                staffUser.setCorpId(contactItem.getCorp_id());
                staffUser.setSeq(contactItem.getSeq());
                staffUser.setStatus(contactItem.getStatus());

                saveList.add(staffUser);
            }
        }
        if (CollectionUtils.isNotEmpty(saveList)) {
            List<List<ThirdPartWeComStaffUser>> partitionList = Lists.partition(saveList, 500);
            for (List<ThirdPartWeComStaffUser> partition : partitionList) {
                thirdPartWeComMapperExt.batchInsertThirdPartWeComStaffUser(partition);
            }
        }
        if (CollectionUtils.isNotEmpty(updateList)) {
            List<List<ThirdPartWeComStaffUser>> partitionList = Lists.partition(updateList, 200);
            for (List<ThirdPartWeComStaffUser> partition : partitionList) {
                thirdPartWeComMapperExt.batchUpdateThirdPartWeComStaffUser(partition);
            }
        }
    }

    private List<ThirdPartWeComStaffUser> getThirdPartWeComStaffUserListByStaffId(Long thirdStaffId) {
        ThirdPartWeComStaffUserExample example = new ThirdPartWeComStaffUserExample();
        example.createCriteria().andThirdStaffIdEqualTo(thirdStaffId);
        return staffUserMapper.selectByExample(example);
    }


    @XxlJob("syncRoomDetail")
    public ReturnT<String> syncRoomDetail(String param) {
        List<ThirdPartWeComStaff> activeStaffList = thirdPartyService.getActiveStaffList();
        CountDownLatch cdl = new CountDownLatch(activeStaffList.size());
        for (ThirdPartWeComStaff staff : activeStaffList) {
            pool.execute(() -> {
                try {
                    syncRoomList(staff);
                } finally {
                    cdl.countDown();
                }
            });
        }
        try {
            cdl.await();
        } catch (InterruptedException e) {
            log.error("syncRoomDetail error", e);
        }
        return ReturnT.SUCCESS;
    }

    public void syncRoomList(ThirdPartWeComStaff staff) {
        List<GetChatroomMembersResponse.RoomInfo> roomInfoList =
                thirdPartyService.getChatroomMembers(new GetChatroomMembersRequest(staff.getThirdUuid(), 100, 0));
        List<ThirdPartWeComRoom> roomList = thirdPartyService.getStaffRoomList(staff.getId());
        Map<String, ThirdPartWeComRoom> roomMap = roomList.stream()
                .collect(Collectors.toMap(ThirdPartWeComRoom::getThirdRoomId, room -> room));
        List<ThirdPartWeComRoom> saveList = new ArrayList<>();
        List<ThirdPartWeComRoom> updateList = new ArrayList<>();
        for (GetChatroomMembersResponse.RoomInfo roomInfo : roomInfoList) {
            String roomId = roomInfo.getRoom_id();
            ThirdPartWeComRoom roomDetail = roomMap.get(roomId);
            if (Objects.isNull(roomDetail)) {
                roomDetail = new ThirdPartWeComRoom();
                roomDetail.setCorpId(staff.getCorpId());
                roomDetail.setStaffId(staff.getId());
                roomDetail.setRoomUrl(roomInfo.getRoomurl());
                roomDetail.setThirdRoomId(roomInfo.getRoom_id());
                roomDetail.setThirdCreateUserId(roomInfo.getCreate_user_id());
                roomDetail.setMemberCount(roomInfo.getTotal());
                roomDetail.setName(roomInfo.getNickname());
                roomDetail.setAddUserStatus(0);
                roomDetail.setSendStatus(0);
                roomDetail.setRoomCreateTime(roomInfo.getCreate_time());
                roomDetail.setCreateTime(new Date());
                roomDetail.setUpdateTime(new Date());
                //roomMapper.insertSelective(roomDetail);
                saveList.add(roomDetail);
            } else {
                roomDetail.setRoomUrl(roomInfo.getRoomurl());
                roomDetail.setThirdRoomId(roomInfo.getRoom_id());
                roomDetail.setThirdCreateUserId(roomInfo.getCreate_user_id());
                roomDetail.setMemberCount(roomInfo.getTotal());
                roomDetail.setName(roomInfo.getNickname());
                roomDetail.setRoomCreateTime(roomInfo.getCreate_time());
                roomDetail.setUpdateTime(new Date());
                if (staff.getAutoCreateRoom() == 1) {
                    if (roomDetail.getMemberCount() >= memberMaxNums) {
                        roomDetail.setAddUserStatus(0);
                    }
                }
                //roomMapper.updateByPrimaryKeySelective(roomDetail);
                updateList.add(roomDetail);
            }
        }
        if (CollectionUtils.isNotEmpty(saveList)) {
            List<List<ThirdPartWeComRoom>> partitionList = Lists.partition(saveList, 500);
            for (List<ThirdPartWeComRoom> partition : partitionList) {
                thirdPartWeComMapperExt.batchInsertThirdPartWeComRoom(partition);
            }
            new Thread(() -> batchSaveRoomConfig(staff)).start();
        }
        if (CollectionUtils.isNotEmpty(updateList)) {
            List<List<ThirdPartWeComRoom>> partitionList = Lists.partition(updateList, 200);
            for (List<ThirdPartWeComRoom> partition : partitionList) {
                thirdPartWeComMapperExt.batchUpdateThirdPartWeComRoom(partition);
            }
        }
        for (GetChatroomMembersResponse.RoomInfo roomInfo : roomInfoList) {
            syncRoomUserList(staff.getThirdUuid(), roomInfo.getRoom_id());
        }
        List<String> roomIds = roomInfoList.stream().map(GetChatroomMembersResponse.RoomInfo::getRoom_id).collect(Collectors.toList());
        roomList.removeIf(room -> roomIds.contains(room.getThirdRoomId()));
        if (CollectionUtils.isNotEmpty(roomList) && CollectionUtils.isNotEmpty(roomInfoList)) {
            roomList.forEach(room -> {
                room.setIsDelete(1);
                room.setUpdateTime(new Date());
                roomMapper.updateByPrimaryKeySelective(room);
            });
        }
    }

    private void batchSaveRoomConfig(ThirdPartWeComStaff staff) {
        ThirdPartyAccountConfigVO accountConfig = thirdPartyAccountService.getAccountConfig(new ThirdPartyConfigGetParam(staff.getId()));
        if (Objects.isNull(accountConfig)) {
            return;
        }
        List<ThirdPartWeComRoom> noConfigRoomList = thirdPartWeComRoomMapperExt.getNoConfigRoomList(staff.getId());
        if (CollectionUtils.isNotEmpty(noConfigRoomList)) {
            for (ThirdPartWeComRoom room : noConfigRoomList) {
                thirdPartyRoomService.saveRoomConfig(room, accountConfig.getId(), accountConfig);
            }
        }
    }

    public void syncRoomUserList(String uuid, String thirdRoomId) {
        GetRoomUserListRequest request = new GetRoomUserListRequest(uuid, Long.valueOf(thirdRoomId));
        List<GetRoomUserListResponse.Member> userList = thirdPartyService.getRoomUserList(request);
        List<Long> currentUniList = userList.stream().map(GetRoomUserListResponse.Member::getUin).collect(Collectors.toList());
        List<ThirdPartWeComRoomUser> existUserList = getThirdPartWeComRoomUserListByRoomId(thirdRoomId);
        List<Long> existUserIdList = existUserList.stream().map(ThirdPartWeComRoomUser::getUin).collect(Collectors.toList());
        Map<Long, ThirdPartWeComRoomUser> existUserMap = existUserList.stream()
                .collect(Collectors.toMap(ThirdPartWeComRoomUser::getUin, roomUser -> roomUser, (a, b) -> a));

        List<ThirdPartWeComRoomUser> saveList = new ArrayList<>();
        List<ThirdPartWeComRoomUser> updateList = new ArrayList<>();
        for (GetRoomUserListResponse.Member user : userList) {
            if (existUserIdList.contains(user.getUin())) {
                ThirdPartWeComRoomUser existUser = existUserMap.get(user.getUin());
                existUser.setUpdateTime(new Date());

                existUser.setUnionid(user.getUnionid());
                existUser.setSex(user.getSex());
                existUser.setMobile(user.getMobile());
                existUser.setAcctid(user.getAcctid());
                existUser.setJoinScene(user.getJoin_scene());
                existUser.setAvatar(user.getAvatar());
                existUser.setEnglishName(user.getEnglish_name());
                existUser.setRealname(user.getRealname());
                existUser.setRoomNotes(user.getRoom_notes());
                existUser.setJoinTime(user.getJointime());
                existUser.setNickname(user.getNickname());
                existUser.setRoomNickname(user.getRoom_nickname());
                existUser.setPosition(user.getPosition());
                existUser.setUin(user.getUin());
                existUser.setInviteUserId(user.getInvite_user_id());
                existUser.setCorpId(user.getCorp_id());

                //roomUserMapper.updateByPrimaryKeySelective(existUser);
                updateList.add(existUser);
            } else {
                ThirdPartWeComRoomUser roomUser = new ThirdPartWeComRoomUser();
                roomUser.setThirdRoomId(thirdRoomId);
                roomUser.setCreateTime(new Date());
                roomUser.setUpdateTime(new Date());

                // 从Member对象复制所有字段值
                roomUser.setUnionid(user.getUnionid());
                roomUser.setSex(user.getSex());
                roomUser.setMobile(user.getMobile());
                roomUser.setAcctid(user.getAcctid());
                roomUser.setJoinScene(user.getJoin_scene());
                roomUser.setAvatar(user.getAvatar());
                roomUser.setEnglishName(user.getEnglish_name());
                roomUser.setRealname(user.getRealname());
                roomUser.setRoomNotes(user.getRoom_notes());
                roomUser.setJoinTime(user.getJointime());
                roomUser.setNickname(user.getNickname());
                roomUser.setRoomNickname(user.getRoom_nickname());
                roomUser.setPosition(user.getPosition());
                roomUser.setUin(user.getUin());
                roomUser.setInviteUserId(user.getInvite_user_id());
                roomUser.setCorpId(user.getCorp_id());

                saveList.add(roomUser);
            }
        }
        if (CollectionUtils.isNotEmpty(saveList)) {
            List<List<ThirdPartWeComRoomUser>> partitionList = Lists.partition(saveList, 500);
            for (List<ThirdPartWeComRoomUser> partition : partitionList) {
                thirdPartWeComMapperExt.batchInsertThirdPartWeComRoomUser(partition);
            }
        }
        if (CollectionUtils.isNotEmpty(updateList)) {
            List<List<ThirdPartWeComRoomUser>> partitionList = Lists.partition(updateList, 200);
            for (List<ThirdPartWeComRoomUser> partition : partitionList) {
                thirdPartWeComMapperExt.batchUpdateThirdPartWeComRoomUser(partition);
            }
        }
        // 删除不存在的用户
        List<Long> deleteList = existUserList.stream()
                .filter(user -> Objects.isNull(user.getQuitTime()))
                .map(ThirdPartWeComRoomUser::getUin)
                .filter(uin -> !currentUniList.contains(uin))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(deleteList)) {
            Long quitTime = System.currentTimeMillis() / 1000;
            thirdPartWeComMapperExt.setRoomUserQuitTime(thirdRoomId, deleteList, quitTime);
        }
    }

    private List<ThirdPartWeComRoomUser> getThirdPartWeComRoomUserListByRoomId(String thirdRoomId) {
        ThirdPartWeComRoomUserExample example = new ThirdPartWeComRoomUserExample();
        example.createCriteria().andThirdRoomIdEqualTo(thirdRoomId);
        return roomUserMapper.selectByExample(example);
    }
}
