package com.tzld.piaoquan.offline.job;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tzld.piaoquan.growth.common.component.HttpPoolClient;
import com.tzld.piaoquan.growth.common.component.ProxyHttpPoolClient;
import com.tzld.piaoquan.growth.common.dao.mapper.*;
import com.tzld.piaoquan.growth.common.model.bo.XxlJobParam;
import com.tzld.piaoquan.growth.common.model.po.*;
import com.tzld.piaoquan.growth.common.service.WeComAccessTokenService;
import com.tzld.piaoquan.growth.common.service.WeComUserService;
import com.tzld.piaoquan.growth.common.utils.DateUtil;
import com.tzld.piaoquan.growth.common.utils.LarkRobotUtil;
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.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.tzld.piaoquan.growth.common.common.constant.RedisConstant.WE_COM_USER_AB_TYPE;
import static com.tzld.piaoquan.growth.common.common.constant.WeComConstant.*;

@Slf4j
@Component
public class WeComUserDataJob {

    @Autowired
    private HttpPoolClient httpPoolClient;

    @Autowired
    private ProxyHttpPoolClient proxyHttpPoolClient;


    @Autowired
    private StaffMapper staffMapper;

    @Autowired
    private WeComUserMapper weComUserMapper;

    @Autowired
    private WeComAccessTokenService weComAccessTokenService;

    @Autowired
    private StaffWithUserMapper staffWithUserMapper;

    @Autowired
    private WeComUserService weComUserService;

    @Autowired
    private CorpMapper corpMapper;

    @Autowired
    private UserCountMapper userCountMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @XxlJob("updateStaffWithUserJob")
    public ReturnT<String> updateStaffWithUser(String param) {
        XxlJobParam xxlJobParam = new XxlJobParam();
        if (StringUtils.isNotEmpty(param)) {
            xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
        }
        CorpExample corpExample = new CorpExample();
        CorpExample.Criteria corpCriteria = corpExample.createCriteria();
        if (xxlJobParam.getCorpId() != null) {
            corpCriteria.andIdEqualTo(xxlJobParam.getCorpId());
        }
        List<Corp> corps = corpMapper.selectByExample(corpExample);
        if (CollectionUtils.isEmpty(corps)) {
            return ReturnT.SUCCESS;
        }
        for (Corp corp : corps) {
            StaffExample staffExample = new StaffExample();
            StaffExample.Criteria staffCriteria = staffExample.createCriteria();
            staffCriteria.andCorpIdEqualTo(corp.getId());
            if (xxlJobParam.getStaffId() != null) {
                staffCriteria.andIdEqualTo(xxlJobParam.getStaffId());
            }
            List<Staff> staffList = staffMapper.selectByExample(staffExample);
            if (CollectionUtils.isEmpty(staffList)) {
                continue;
            }
            for (Staff staff : staffList) {
                updateUserList(staff, corp.getId());
            }
        }
        return ReturnT.SUCCESS;
    }


    private void updateUserList(Staff staff, Long corpId) {
        try {
            String cursor = "";
            do {
                String res = getUserDetailList(staff.getCarrierId(), cursor, corpId);
                log.info("updateUserList res={} cursor={}", res, cursor);
                JSONObject jsonObject = JSONObject.parseObject(res);
                Integer errCode = jsonObject.getInteger("errcode");
                if (errCode != 0) {
                    log.error("updateUserList error carrierId={} cursor={}", staff.getCarrierId(), cursor);
                    return;
                }
                JSONArray externalContactList = jsonObject.getJSONArray("external_contact_list");
                for (int i = 0; i < externalContactList.size(); i++) {
                    JSONObject externalContact = externalContactList.getJSONObject(i).getJSONObject("external_contact");
                    JSONObject followInfo = externalContactList.getJSONObject(i).getJSONObject("follow_info");
                    Long createAt = followInfo.getLong("createtime");
                    String externalUserId = externalContact.getString("external_userid");
                    String name = externalContact.getString("name");
                    String unionId = externalContact.getString("unionid");
                    String avatar = externalContact.getString("avatar");
                    Integer type = externalContact.getInteger("type");
                    Integer gender = externalContact.getInteger("gender");
                    WeComUserExample example = new WeComUserExample();
                    example.createCriteria().andExternalUserIdEqualTo(externalUserId);
                    List<WeComUser> weComUserList = weComUserMapper.selectByExample(example);
                    WeComUser weComUser = new WeComUser();
                    weComUser.setExternalUserId(externalUserId);
                    weComUser.setName(name);
                    weComUser.setType(type);
                    weComUser.setUnionId(unionId);
                    weComUser.setGender(gender);
                    weComUser.setAvatar(avatar);
                    weComUser.setCreatedAt(createAt);
                    Long userId;
                    if (CollectionUtils.isEmpty(weComUserList)) {
                        Long increment = redisTemplate.opsForValue().increment(WE_COM_USER_AB_TYPE);
                        if (increment != null) {
                            weComUser.setAbtype("ab" + increment % 10);
                        }
                        weComUserMapper.insertSelective(weComUser);
                        userId = weComUser.getId();
                    } else {
                        WeComUser oldWeComUser = weComUserList.get(0);
                        weComUser.setId(oldWeComUser.getId());
                        weComUserMapper.updateByPrimaryKeySelective(weComUser);
                        userId = oldWeComUser.getId();
                    }
                    if (userId == null) {
                        continue;
                    }
                    StaffWithUserExample staffWithUserExample = new StaffWithUserExample();
                    staffWithUserExample.createCriteria().andStaffIdEqualTo(staff.getId()).andUserIdEqualTo(userId);
                    List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(staffWithUserExample);
                    if (CollectionUtils.isEmpty(staffWithUserList)) {
                        StaffWithUser staffWithUser = new StaffWithUser();
                        staffWithUser.setStaffId(staff.getId());
                        staffWithUser.setUserId(userId);
                        staffWithUserMapper.insertSelective(staffWithUser);
                    }
                }
                String nextCursor = jsonObject.getString("next_cursor");
                if (cursor.equals(nextCursor)) {
                    break;
                }
                cursor = nextCursor;
            } while (StringUtils.isNotEmpty(cursor));
        } catch (IOException e) {
            LarkRobotUtil.sendMessage("updateUser error" + e);
            log.error("updateUser error", e);
        }
    }

    private String getUserDetailList(String userId, String cursor, Long corpId) throws IOException {
        String accessToken = weComAccessTokenService.getWeComAccessToken(corpId);
        String url = POST_WE_COM_GET_BY_USER
                + "?access_token=" + accessToken;
        JSONObject param = new JSONObject();
        JSONArray userIdList = new JSONArray();
        userIdList.add(userId);
        param.put("userid_list", userIdList);
        param.put("limit", 100);
        if (StringUtils.isNotEmpty(cursor)) {
            param.put("cursor", cursor);
        }
        if (corpId == 1L) {
            return httpPoolClient.post(url, param.toJSONString());
        } else {
            return proxyHttpPoolClient.post(url, param.toJSONString());
        }
    }

    @XxlJob("insertStaffWithUserJob")
    public ReturnT<String> insertStaffWithUserJob(String param) {
        try {
            XxlJobParam xxlJobParam = new XxlJobParam();
            if (StringUtils.isNotEmpty(param)) {
                xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
            }
            CorpExample corpExample = new CorpExample();
            CorpExample.Criteria corpCriteria = corpExample.createCriteria();
            if (xxlJobParam.getCorpId() != null) {
                corpCriteria.andIdEqualTo(xxlJobParam.getCorpId());
            }
            List<Corp> corps = corpMapper.selectByExample(corpExample);
            for (Corp corp : corps) {
                StaffExample staffExample = new StaffExample();
                StaffExample.Criteria staffCriteria = staffExample.createCriteria();
                staffCriteria.andCorpIdEqualTo(corp.getId());
                if (xxlJobParam.getStaffId() != null) {
                    staffCriteria.andIdEqualTo(xxlJobParam.getStaffId());
                }
                List<Staff> staffList = staffMapper.selectByExample(staffExample);
                for (Staff staff : staffList) {
                    List<String> existExternalUserIds = getUserList(staff.getCarrierId(), corp.getId());
                    List<String> allExternalUserIds = staffWithUserMapper.selectExternalUserIdByStaffId(staff.getId());
                    if (!CollectionUtils.isEmpty(existExternalUserIds)) {
                        allExternalUserIds.removeAll(existExternalUserIds);
                    }
                    if (!CollectionUtils.isEmpty(allExternalUserIds)) {
                        for (String delExternalUserId : allExternalUserIds) {
                            weComUserService.delStaffWithUser(delExternalUserId, staff.getCarrierId(), corp.getId(),
                                    System.currentTimeMillis());
                        }
                    }
                    if (CollectionUtils.isEmpty(existExternalUserIds)) {
                        continue;
                    }
                    for (String externalUserId : existExternalUserIds) {
                        weComUserService.insertStaffWithUser(externalUserId, staff, corp.getId());
                    }
                }
            }
        } catch (Exception e) {
            LarkRobotUtil.sendMessage("insertStaffWithUserJob error" + e);
            log.error("insertStaffWithUserJob error", e);
        }

        return ReturnT.SUCCESS;

    }

    public List<String> getUserList(String userId, Long corpId) throws IOException {
        String weComAccessToken = weComAccessTokenService.getWeComAccessToken(corpId);
        String url = String.format(GET_WE_COM_EXTERNAL_CONTACT_LIST + "?access_token=%s&userid=%s", weComAccessToken, userId);
        String res;
        if (corpId == 1L) {
            res = httpPoolClient.get(url);
        } else {
            res = proxyHttpPoolClient.get(url);
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        Integer errcode = jsonObject.getInteger("errcode");
        if (errcode == 0) {
            return jsonObject.getJSONArray("external_userid").stream().map(String::valueOf).collect(Collectors.toList());
        }
        return null;
    }

    @XxlJob("statisticsUserCountJob")
    public ReturnT<String> statisticsUserCount(String param) {
        refreshTag();
        StaffExample staffExample = new StaffExample();
        staffExample.createCriteria().andIsDeleteEqualTo(0).andCorpIdEqualTo(1L);
        List<Staff> staffList = staffMapper.selectByExample(staffExample);
        String date;
        if (StringUtils.isEmpty(param)) {
            date = DateUtil.getBeforeDayDateString1();
        } else {
            date = param;
        }
        for (Staff staff : staffList) {
            Map<String, Integer> userCountRes = getUserList(staff, date);
            if (userCountRes == null || userCountRes.get("count") == 0) {
                continue;
            }
            UserCountExample userCountExample = new UserCountExample();
            userCountExample.createCriteria().andStaffIdEqualTo(staff.getId()).andDateEqualTo(date);
            List<UserCount> userCounts = userCountMapper.selectByExample(userCountExample);
            if (CollectionUtils.isEmpty(userCounts)) {
                UserCount userCount = new UserCount();
                userCount.setStaffId(staff.getId());
                userCount.setStaffName(staff.getRemark());
                userCount.setAllCount(userCountRes.get("count"));
                userCount.setNewCount(userCountRes.get("newCount"));
                userCount.setDate(date);
                userCountMapper.insertSelective(userCount);
            } else {
                UserCount userCount = userCounts.get(0);
                userCount.setAllCount(userCountRes.get("count"));
                userCount.setNewCount(userCountRes.get("newCount"));
                userCountMapper.updateByPrimaryKeySelective(userCount);
            }
        }
        return ReturnT.SUCCESS;
    }


    private Map<String, Integer> getUserList(Staff staff, String date) {
        Map<String, Integer> result = new HashMap<>();
        int count = 0;
        int newCount = 0;
        try {
            String cursor = "";
            do {
                String res = getUserDetailList(staff.getCarrierId(), cursor, staff.getCorpId());
                log.info("getUserList res={} cursor={}", res, cursor);
                JSONObject jsonObject = JSONObject.parseObject(res);
                Integer errCode = jsonObject.getInteger("errcode");
                if (errCode != 0) {
                    //log.error("getUserList error carrierId={} cursor={}", staff.getCarrierId(), cursor);
                    return null;
                }
                JSONArray externalContactList = jsonObject.getJSONArray("external_contact_list");
                for (int i = 0; i < externalContactList.size(); i++) {
                    JSONObject externalContact = externalContactList.getJSONObject(i).getJSONObject("external_contact");
                    String externalUserId = externalContact.getString("external_userid");
                    JSONObject followInfo = externalContactList.getJSONObject(i).getJSONObject("follow_info");
                    Long createAt = followInfo.getLong("createtime");
                    String dateString = DateUtil.getDateString(createAt * 1000, "yyyy-MM-dd");
                    if (dateString.equals(date)) {
                        newCount++;
                    }
                    count++;
                    Long userId = weComUserMapper.selectIdByExternalUserId(externalUserId);
                    userId = addAndUpdateUser(externalContact, staff.getCorpId(), externalUserId, createAt, staff.getId(), userId);
                    JSONArray tagIds = followInfo.getJSONArray("tag_id");
                    if (!CollectionUtils.isEmpty(tagIds)) {
                        List<String> tagIdList = tagIds.toJavaList(String.class);
                        weComUserService.updateUserWithTag(userId, tagIdList);
//                        for (String tagId : tagIdList) {
//                            TagExample example = new TagExample();
//                            example.createCriteria().andTagIdEqualTo(tagId);
//                            List<Tag> tags = tagMapper.selectByExample(example);
//                            if (!CollectionUtils.isEmpty(tags)) {
//                                Tag tag = tags.get(0);
//                                UserWithTag userWithTag = new UserWithTag();
//                                userWithTag.setUserId(userId);
//                                userWithTag.setTagId(tag.getId());
//                                weComUserService.addUserWithTag(userWithTag);
//                            }
//                        }
                    } else {
                        weComUserService.delAllUserTag(userId);
                    }
                }
                String nextCursor = jsonObject.getString("next_cursor");
                if (cursor.equals(nextCursor)) {
                    break;
                }
                cursor = nextCursor;
            } while (StringUtils.isNotEmpty(cursor));
        } catch (IOException e) {
            log.error("getUserList error", e);
        }
        result.put("count", count);
        result.put("newCount", newCount);
        return result;
    }

//    @XxlJob("getUserTagJob")
//    public ReturnT<String> getUserTag(String param) {
//        try {
//            refreshTag();
//            XxlJobParam xxlJobParam = new XxlJobParam();
//            if (StringUtils.isNotEmpty(param)) {
//                xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
//            }
//            CorpExample corpExample = new CorpExample();
//            CorpExample.Criteria corpCriteria = corpExample.createCriteria();
//            if (xxlJobParam.getCorpId() != null) {
//                corpCriteria.andIdEqualTo(xxlJobParam.getCorpId());
//            }
//            List<Corp> corps = corpMapper.selectByExample(corpExample);
//            for (Corp corp : corps) {
//                StaffExample staffExample = new StaffExample();
//                StaffExample.Criteria staffCriteria = staffExample.createCriteria();
//                staffCriteria.andCorpIdEqualTo(corp.getId());
//                List<Long> staffIds = new ArrayList<>();
//                if (xxlJobParam.getStaffId() != null) {
//                    staffIds.add(xxlJobParam.getStaffId());
//                }
//                if (!CollectionUtils.isEmpty(xxlJobParam.getStaffIds())) {
//                    staffIds.addAll(xxlJobParam.getStaffIds());
//                }
//                if (!CollectionUtils.isEmpty(staffIds)) {
//                    staffCriteria.andIdIn(staffIds);
//                }
//                List<Staff> staffList = staffMapper.selectByExample(staffExample);
//                for (Staff staff : staffList) {
//                    List<String> existExternalUserIds = getUserList(staff.getCarrierId(), corp.getId());
//                    for (String externalUserId : existExternalUserIds) {
//                        JSONObject userDetail = weComUserService.getUserDetail(externalUserId, corp.getId());
//                        JSONObject externalContact = userDetail.getJSONObject("external_contact");
//                        JSONArray followUserList = userDetail.getJSONArray("follow_user");
//                        Long createAt = null;
//                        for (int i = 0; i < followUserList.size(); i++) {
//                            JSONObject followUser = followUserList.getJSONObject(i);
//                            if (createAt == null) {
//                                createAt = followUser.getLong("createtime");
//                            } else {
//                                createAt = Math.min(createAt, followUser.getLong("createtime"));
//                            }
//                            JSONArray tagIds = followUser.getJSONArray("tags");
//                            if (!CollectionUtils.isEmpty(tagIds)) {
//                                List<String> tagIdList = new ArrayList<>();
//                                for (int j = 0; j < tagIds.size(); j++) {
//                                    JSONObject jsonObject = tagIds.getJSONObject(j);
//                                    tagIdList.add(jsonObject.getString("tag_id"));
//                                }
//                                for (String tagId : tagIdList) {
//                                    TagExample example = new TagExample();
//                                    example.createCriteria().andTagIdEqualTo(tagId);
//                                    List<Tag> tags = tagMapper.selectByExample(example);
//                                    if (!CollectionUtils.isEmpty(tags)) {
//                                        Long userId = weComUserMapper.selectIdByExternalUserId(externalUserId);
//                                        userId = addAndUpdateUser(externalContact, corp.getId(), externalUserId,
//                                                createAt, staff.getId(), userId);
//                                        Tag tag = tags.get(0);
//                                        UserWithTag userWithTag = new UserWithTag();
//                                        userWithTag.setUserId(userId);
//                                        userWithTag.setTagId(tag.getId());
//                                        weComUserService.addUserWithTag(userWithTag);
//                                    }
//                                }
//                            }
//                        }
//                    }
//                }
//            }
//        } catch (Exception e) {
//            log.error("getUserTag error", e);
//        }
//
//        return ReturnT.SUCCESS;
//
//    }


    public void refreshTag() {
        try {
            String weComAccessToken = weComAccessTokenService.getWeComAccessToken(1L);
            String url = String.format(POST_CORP_TAG_LIST + "?access_token=%s", weComAccessToken);
            String res = httpPoolClient.post(url);
            JSONObject jsonObject = JSONObject.parseObject(res);
            Integer errcode = jsonObject.getInteger("errcode");
            if (errcode == 0) {
                JSONArray tagGroup = jsonObject.getJSONArray("tag_group");
                if (!tagGroup.isEmpty()) {
                    for (int i = 0; i < tagGroup.size(); i++) {
                        JSONObject tagGroupJSONObject = tagGroup.getJSONObject(i);
                        String groupId = tagGroupJSONObject.getString("group_id");
                        String groupName = tagGroupJSONObject.getString("group_name");
                        JSONArray tags = tagGroupJSONObject.getJSONArray("tag");
                        if (tags.isEmpty()) {
                            continue;
                        }
                        for (int j = 0; j < tags.size(); j++) {
                            JSONObject tagsJSONObject = tags.getJSONObject(j);
                            String tagId = tagsJSONObject.getString("id");
                            String tagName = tagsJSONObject.getString("name");
                            Tag tag = new Tag();
                            tag.setTagGroupId(groupId);
                            tag.setTagGroupName(groupName);
                            tag.setTagId(tagId);
                            tag.setTagName(tagName);
                            addAndUpdateTag(tag);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("refreshTag error", e);
        }

    }

    private void addAndUpdateTag(Tag tag) {
        TagExample example = new TagExample();
        example.createCriteria().andTagGroupIdEqualTo(tag.getTagGroupId()).andTagIdEqualTo(tag.getTagId());
        List<Tag> tags = tagMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(tags)) {
            tagMapper.insertSelective(tag);
        } else {
            tag.setId(tags.get(0).getId());
            tagMapper.updateByPrimaryKeySelective(tag);
        }
    }

    private Long addAndUpdateUser(JSONObject externalContact, Long corpId, String externalUserId, Long createAt, Long staffId, Long userId) {
        String name = externalContact.getString("name");
        String unionId = externalContact.getString("unionid");
        String avatar = externalContact.getString("avatar");
        Integer type = externalContact.getInteger("type");
        Integer gender = externalContact.getInteger("gender");
        if (userId == null) {
            WeComUser weComUser = new WeComUser();
            weComUser.setCorpId(corpId);
            weComUser.setExternalUserId(externalUserId);
            weComUser.setName(name);
            weComUser.setType(type);
            weComUser.setUnionId(unionId);
            weComUser.setGender(gender);
            weComUser.setAvatar(avatar);
            weComUser.setCreatedAt(createAt);
            Long increment = redisTemplate.opsForValue().increment(WE_COM_USER_AB_TYPE);
            if (increment != null) {
                weComUser.setAbtype("ab" + increment % 10);
            }
            weComUserMapper.insertSelective(weComUser);
            userId = weComUser.getId();
            StaffWithUser staffWithUser = new StaffWithUser();
            staffWithUser.setStaffId(staffId);
            staffWithUser.setUserId(userId);
            staffWithUserMapper.insertSelective(staffWithUser);
        } else {
            WeComUser weComUser = new WeComUser();
            weComUser.setId(userId);
            weComUser.setName(name);
            weComUser.setType(type);
            weComUser.setUnionId(unionId);
            weComUser.setGender(gender);
            weComUser.setAvatar(avatar);
            weComUser.setIsDelete(0);
            weComUserMapper.updateByPrimaryKeySelective(weComUser);
            StaffWithUserExample example = new StaffWithUserExample();
            example.createCriteria().andStaffIdEqualTo(staffId).andUserIdEqualTo(userId);
            List<StaffWithUser> staffWithUsers = staffWithUserMapper.selectByExample(example);
            if (CollectionUtils.isEmpty(staffWithUsers)) {
                StaffWithUser staffWithUser = new StaffWithUser();
                staffWithUser.setStaffId(staffId);
                staffWithUser.setUserId(userId);
                staffWithUserMapper.insertSelective(staffWithUser);
            }
        }
        return userId;
    }

}
