package com.sw.mes.dingTalk.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.sw.mes.base.global.GlobalSwitch;
import com.sw.mes.base.global.GlobalSwitchNamespace;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.core.dto.SeedMassageDto;
import com.sw.mes.core.enums.SeedMassageEnum;
import com.sw.mes.dingTalk.dto.*;
import com.sw.mes.dingTalk.entity.DingTalkMessageLog;
import com.sw.mes.dingTalk.service.DingTalkMessageLogService;
import com.sw.mes.dingTalk.service.DingTalkService;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

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

/**
 * @author lf
 * @description
 * @date 2024/1/23 20:53
 */
@Slf4j
@Service
public class DingTalkServiceImpl implements DingTalkService {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private DictionaryItemService dictionaryItemService;
    @Autowired
    private DingTalkMessageLogService dingTalkMessageLogService;

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    @Qualifier(value = "yBMesThreadPoolTaskExecutor")
    private ThreadPoolTaskExecutor ybMesThreadPoolExecutor;

    @Override
    public void seedMassage(SeedMassageDto dto) throws JsonProcessingException {
        if (!GlobalSwitch.enable(GlobalSwitchNamespace.NAMESPACE_COMMON_SWITCH, "dingdingmsg", true)) {
            return;
        }
        AccessTokenDto accessToken = getAccessToken();
        MicroAppDto microApp = getMicroApp(accessToken);
        List<Long> deptIds = getDeptIds(accessToken, microApp.getDeptIds());
//        去重部门id相同的数据
        List<Long> distinctDeptIdList = deptIds.stream().distinct().collect(Collectors.toList());
        List<String> deptUserIds = getDeptUserIds(accessToken, distinctDeptIdList, microApp.getUserIds());
//        去重用户id相同的数据
        List<String> userIdList = deptUserIds.stream().distinct().collect(Collectors.toList());
        userIdList.add("971853425");
        DingTalkMessageLog dingTalkMessageLog = fromDto(dto);
        dingTalkMessageLogService.saveOrUpdate(dingTalkMessageLog);
        if (dto.getStatus() == SeedMassageEnum.GROUP_AND_INDIVIDUAL) {
            seedIndividualMessages(accessToken, userIdList, dto);
            seedGroupOfMessages(dto);
        } else if (dto.getStatus() == SeedMassageEnum.GROUP) {
            seedGroupOfMessages(dto);
        } else if (dto.getStatus() == SeedMassageEnum.INDIVIDUAL) {
            seedIndividualMessages(accessToken, userIdList, dto);
        }
    }

    @Override
    public void seedIndividualMessage(SeedIndividualMessageDto dto) throws JsonProcessingException {
        List<String> userIdList = dto.getUserIdList().stream().distinct().collect(Collectors.toList());
        buildDingTalkMessageLog(dto);
        AccessTokenDto accessToken = getAccessToken();
        SeedMassageDto seedMassageDto = new SeedMassageDto();
        seedMassageDto.setContent(dto.getContent());
        seedMassageDto.setScene(dto.getScene());
        seedMassageDto.setStatus(SeedMassageEnum.INDIVIDUAL);
        seedMassageDto.setSource(dto.getSource());
        seedIndividualMessages(accessToken, userIdList, seedMassageDto);

    }

    @Override
    public void robotSeedMessage(String content, List<String> groupNameList, String source, List<String> sceneList, SeedMassageEnum status){
        ybMesThreadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SeedMassageDto seedMassageDto = new SeedMassageDto();
                    seedMassageDto.setContent(content);
                    seedMassageDto.setScene(sceneList);
                    seedMassageDto.setGroupName(groupNameList);
                    seedMassageDto.setStatus(status);
                    seedMassageDto.setSource(source);
                    DingTalkServiceImpl.this.seedMassage(seedMassageDto);
                } catch (Exception e) {
                    log.error("晶彩消息推送失败消息内容:{},机器人群名称:{},机器人使用场景:{},消息来源:{},发送人群:{},错误内容:{}",content,groupNameList,sceneList,source,status,e);
                }
            }
        });
    }


    private void buildDingTalkMessageLog(SeedIndividualMessageDto dto) {
        DingTalkMessageLog dingTalkMessageLog = new DingTalkMessageLog();
        dingTalkMessageLog.setContent(dto.getContent());
        dingTalkMessageLog.setScene(dto.getScene().toString());
        dingTalkMessageLog.setStatus(2);
        dingTalkMessageLog.setSource(dto.getSource());
        dingTalkMessageLog.setCreateDate(new Date());
        dingTalkMessageLogService.saveOrUpdate(dingTalkMessageLog);
    }

    /**
     * 机器人发送群消息
     */
    private void seedGroupOfMessages(SeedMassageDto dto) throws JsonProcessingException {
        Assert.isTrue(!CollectionUtils.isEmpty(dto.getGroupName()), "需要发送消息的群名称不能为空");
        List<String> groupName = dto.getGroupName();
        for (String name : groupName) {
            String url = dictionaryItemService.findByThemeValueAndNameAndEnable("jkGroupRobot", name, true).getValue();
            String msg = buildMsgBody(dto.getContent());
            // 请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> httpEntity = new HttpEntity<>(msg, headers);
            String resp = restTemplate.postForObject(url, httpEntity, String.class);
            log.info("机器人发送消息给群:{}", objectMapper.writeValueAsString(resp));
        }
    }

    /**
     * 构建消息体
     *
     * @param content 发送的内容
     * @return 消息体
     */
    private String buildMsgBody(String content) throws JsonProcessingException {
        Map<String, Object> msgBody = new HashMap<>();
        msgBody.put("msgtype", "text");

        Map<String, Object> at = new HashMap<>();
        at.put("isAtAll", false);
        msgBody.put("at", at);

        Map<String, String> text = new HashMap<>();
        text.put("content", content);
        msgBody.put("text", text);
        return objectMapper.writeValueAsString(msgBody);
    }

    /**
     * 机器人批量发送个人消息
     */
    private void seedIndividualMessages(AccessTokenDto accessToken, List<String> userIdList, SeedMassageDto dto) throws JsonProcessingException {
        Assert.isTrue(!CollectionUtils.isEmpty(dto.getScene()) || null != dto.getContent(), "机器人用途不存在或者发送消息为空");
        for (String name : dto.getScene()) {
            String robotJk = dictionaryItemService.findByThemeValueAndNameAndEnable("jkIndividualRobot", name, true).getValue();
            if (!robotJk.isEmpty()) {
                MessageContentDto messageContentDto = new MessageContentDto();
                messageContentDto.setContent(dto.getContent());
                Gson gson = new Gson();
                String message = gson.toJson(messageContentDto);
                int userListSize = 20;
                ArrayList<String> userList = new ArrayList<>();
                for (String s : userIdList) {
                    userList.add(s);
                    if (userList.size() == userListSize) {
                        Map<String, Object> msgBody = new HashMap<>();
                        msgBody.put("robotCode", robotJk);//机器人编码
                        msgBody.put("userIds", userList);
                        msgBody.put("msgKey", "sampleText");
                        msgBody.put("msgParam", message);
                        HttpHeaders headers = new HttpHeaders();
                        headers.set("x-acs-dingtalk-access-token", accessToken.getAccessToken());
                        headers.setContentType(MediaType.APPLICATION_JSON);
                        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(msgBody, headers);
                        ResponseEntity<String> response = restTemplate.postForEntity("https://api.dingtalk.com//v1.0/robot/oToMessages/batchSend", httpEntity, String.class);
                        String resp = response.getBody();
//                MessageDto messageDto = objectMapper.readValue(resp, MessageDto.class);
                        log.info("机器人发送消息给个人消息:{}", objectMapper.writeValueAsString(resp));
                        userList.clear();
                    }
                }
                if (!CollectionUtils.isEmpty(userList)) {
                    Map<String, Object> msgBody = new HashMap<>();
                    msgBody.put("robotCode", robotJk);//机器人编码
                    msgBody.put("userIds", userList);
                    msgBody.put("msgKey", "sampleText");
                    msgBody.put("msgParam", message);
                    HttpHeaders headers = new HttpHeaders();
                    headers.set("x-acs-dingtalk-access-token", accessToken.getAccessToken());
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(msgBody, headers);
                    ResponseEntity<String> response = restTemplate.postForEntity("https://api.dingtalk.com//v1.0/robot/oToMessages/batchSend", httpEntity, String.class);
                    String resp = response.getBody();
//                MessageDto messageDto = objectMapper.readValue(resp, MessageDto.class);
                    log.info("机器人发送消息给个人消息:{}", objectMapper.writeValueAsString(resp));
                }
            }
        }
    }

    private DingTalkMessageLog fromDto(SeedMassageDto dto) {
        DingTalkMessageLog map = modelMapper.map(dto, DingTalkMessageLog.class);
        map.setStatus(dto.getStatus().getKey());
        if (!dto.getScene().isEmpty()) {
            map.setScene(dto.getScene().toString());
        }
        if (!dto.getGroupName().isEmpty()) {
            map.setGroupName(dto.getGroupName().toString());
        }
        map.setCreateDate(new Date());
        return map;
    }

    /**
     * 根据部门id查询所有子部门id
     */
    private List<Long> getDeptIds(AccessTokenDto accessToken, List<Long> deptIds) throws JsonProcessingException {
        List<Long> idList = new ArrayList<>();
        for (Long deptId : deptIds) {
            idList.add(deptId);
            List<Long> subDeptIds = getSubDeptIds(accessToken, deptId);
            if (!CollectionUtils.isEmpty(subDeptIds)) {
                idList.addAll(subDeptIds);
                getDeptIds(accessToken, subDeptIds);
            }
        }
        return idList;
    }

    private List<Long> getSubDeptIds(AccessTokenDto accessToken, Long deptId) throws JsonProcessingException {
        Map<String, Object> msgBody = new HashMap<>();
        msgBody.put("dept_id", deptId);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(msgBody, headers);
        UriComponentsBuilder url = UriComponentsBuilder.fromUriString("https://oapi.dingtalk.com/topapi/v2/department/listsubid")
                .queryParam("access_token", accessToken.getAccessToken());
        ResponseEntity<String> response = restTemplate.postForEntity(url.toUriString(), httpEntity, String.class);
        String resp = response.getBody();
        DeptIdDto deptIdDto = objectMapper.readValue(resp, DeptIdDto.class);
        Assert.notNull(deptIdDto, "查询子部门id失败");
        List<Long> deptIdList = deptIdDto.getDeptIdList();
        if (!CollectionUtils.isEmpty(deptIdList)) {
            return deptIdList;
        } else {
            return null;
        }
    }


    /**
     * 获取企业内部应用微应用的可使用范围
     */
    private MicroAppDto getMicroApp(AccessTokenDto accessToken) {
        String agentId = dictionaryItemService.findByThemeValueAndNameAndEnable("jkRobotConfig", "agentId", true).getValue();

        HttpHeaders headers = new HttpHeaders();
        headers.set("x-acs-dingtalk-access-token", accessToken.getAccessToken());
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Long> pathParams = new HashMap<>();
        pathParams.put("agentId", Long.valueOf(agentId));
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
        String url = "https://api.dingtalk.com/v1.0/microApp/apps/{agentId}/scopes";
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class, pathParams);
        String resp = response.getBody();
        JSONObject result = JSON.parseObject(resp).getJSONObject("result");
        MicroAppDto microAppDto = result.toJavaObject(MicroAppDto.class);
        Assert.notNull(microAppDto, "获取企业内部应用信息失败!!!");
        return microAppDto;
    }

    /**
     * 获取部门用户id
     */
    private List<String> getDeptUserIds(AccessTokenDto accessToken, List<Long> distinctDeptIdList, List<String> userIds) throws JsonProcessingException {
        ArrayList<String> userIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userIds)) {
            userIdList.addAll(userIds);
        }
        for (Long deptId : distinctDeptIdList) {
            Map<String, Object> msgBody = new HashMap<>();
            msgBody.put("dept_id", deptId);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(msgBody, headers);
            UriComponentsBuilder url = UriComponentsBuilder.fromUriString("https://oapi.dingtalk.com/topapi/user/listid")
                    .queryParam("access_token", accessToken.getAccessToken());
            ResponseEntity<String> response = restTemplate.postForEntity(url.toUriString(), httpEntity, String.class);
            String resp = response.getBody();
            DeptUserDto deptUserDto = objectMapper.readValue(resp, DeptUserDto.class);
            Assert.notNull(deptUserDto, "部门用户信息不存在");
            List<String> userId = deptUserDto.getUserIdList();
            if (!CollectionUtils.isEmpty(userId)) {
                userIdList.addAll(userIds);
            }
        }
        Assert.isTrue(!CollectionUtils.isEmpty(userIdList), "未查询到用户id");
        return userIdList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 获取token信息
     */
    private AccessTokenDto getAccessToken() throws JsonProcessingException {

        String appKey = dictionaryItemService.findByThemeValueAndNameAndEnable("jkRobotConfig", "appKey", true).getValue();
        String appSecret = dictionaryItemService.findByThemeValueAndNameAndEnable("jkRobotConfig", "appSecret", true).getValue();

        Map<String, Object> msgBody = new HashMap<>();
        msgBody.put("appKey", appKey);
        msgBody.put("appSecret", appSecret);
// 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(msgBody, headers);
        ResponseEntity<String> response = restTemplate.postForEntity("https://api.dingtalk.com/v1.0/oauth2/accessToken", httpEntity, String.class);
        String resp = response.getBody();
        AccessTokenDto accessTokenDto = objectMapper.readValue(resp, AccessTokenDto.class);
        Assert.notNull(accessTokenDto.getAccessToken(), "token不存在");
        return accessTokenDto;
    }
}
