package com.usky.pm.service.config;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.tea.TeaException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiReportCreateRequest;
import com.dingtalk.api.request.OapiV2UserGetbymobileRequest;
import com.dingtalk.api.response.OapiReportCreateResponse;
import com.dingtalk.api.response.OapiV2UserGetbymobileResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.usky.common.core.bean.ApiResult;
import com.usky.common.core.exception.BusinessException;
import com.usky.pm.constant.dingTalkConstant;
import com.usky.pm.domain.MceMbuser;
import com.usky.pm.domain.PmWorkContent;
import com.usky.pm.domain.PmWorkReport;
import com.usky.pm.mapper.MceMbuserMapper;
import com.usky.pm.mapper.PmWorkReportMapper;
import com.usky.pm.mapper.SysUserMapper;
import com.usky.system.RemoteMceService;
import com.usky.system.domain.MceRequestVO;
import com.usky.system.domain.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description：TODO
 * @author： fu
 * @create： 2024-07-30 10:32
 */
@Slf4j
@Configuration
public class DingTalkAndMessage {

    private static final String INFO_TITLE = "报告提醒";
    private static final String INFO_CONTENT = "的报告";
    private static final int INFO_TYPE = 5;

    @Autowired
    private RemoteMceService remoteMceService;

    @Autowired
    private MceMbuserMapper mceMbuserMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PmWorkReportMapper pmWorkReportMapper;

    /**
     * 指定请求
     *
     * @return
     * @throws Exception
     */
    public static com.aliyun.dingtalkoauth2_1_0.Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        config.method = "POST";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    /**
     * 获取钉钉企业内部AccessToken
     *
     * @return
     * @throws Exception
     */
    public String getDingTalkToken() {
        GetAccessTokenResponse responseBody = new GetAccessTokenResponse();
        com.aliyun.dingtalkoauth2_1_0.Client client = null;
        try {
            client = createClient();
        } catch (Exception e) {
            log.error("DingTalkAndMessage client = createClient() 获取钉钉token异常：" + e);
        }
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
                .setAppKey(dingTalkConstant.DING_TALK_CLIENT_ID)
                .setAppSecret(dingTalkConstant.DING_TALK_CLIENT_SECRET);
        try {
            responseBody = client.getAccessToken(getAccessTokenRequest);
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                log.error("获取钉钉token异常：" + err.code + err.message);
            }
        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                log.error("DingTalkAndMessage TeaException err = new TeaException(_err.getMessage(), _err) 获取钉钉token异常：" + err.code + err.message);
            }
        }
        return responseBody.getBody().accessToken;
    }

    /**
     * 获取钉钉userId，优先从数据库中找，没有则调用钉钉接口查
     *
     * @param userId userid
     * @return
     */
    public String getDingTalkUserId(Long userId) {
        String dingTalkId = "";
        if (userId == null) {
            return dingTalkId;
        }
        SysUser user = userPhoneNumber(userId);
        String mobile = user.getPhonenumber();
        String userName = user.getUserName();
        LocalDateTime now = LocalDateTime.now();

        // 先看用户是否存在配置
        MceMbuser mceMbuser = getMceMbuser(userId);
        if (mceMbuser != null) {
            String dingId = mceMbuser.getDingTalkId();
            if (StringUtils.isNotBlank(dingId)) {
                return dingId;
            } else {
                dingTalkId = getDingTalkId(userId, mobile, dingTalkId);

                // 钉钉userid存入注册表
                MceMbuser mbuser = new MceMbuser();
                mbuser.setDingTalkId(dingTalkId);
                mbuser.setPhone(mobile);
                mbuser.setUserId(userId);
                mbuser.setUpdateBy(userName);
                mbuser.setUpdateTime(now);
                mceMbuserMapper.updateById(mbuser);
            }
        } else {
            dingTalkId = getDingTalkId(userId, mobile, dingTalkId);

            // 钉钉userid存入注册表
            MceMbuser mbuser = new MceMbuser();
            mbuser.setDingTalkId(dingTalkId);
            mbuser.setPhone(mobile);
            mbuser.setUserId(userId);
            mbuser.setCreateBy(userName);
            mbuser.setCreateTime(now);
            mceMbuserMapper.insert(mbuser);
        }
        return dingTalkId;
    }

    /**
     * 获取用户 消息中心_注册表信息
     *
     * @param userId
     * @return
     */
    private MceMbuser getMceMbuser(Long userId) {
        LambdaQueryWrapper<MceMbuser> dingTalkQuery = Wrappers.lambdaQuery();
        dingTalkQuery.eq(MceMbuser::getUserId, userId);
        return mceMbuserMapper.selectOne(dingTalkQuery);
    }

    /**
     * 获取钉钉userId
     *
     * @param userId 平台userid
     * @return
     */
    private String getDingTalkId(Long userId, String mobile, String dingTalkId) {
        try {
            String accessToken = getDingTalkToken();
            DingTalkClient client = new DefaultDingTalkClient(dingTalkConstant.DING_TALK_USERID_URL);
            OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
            req.setMobile(mobile);
            OapiV2UserGetbymobileResponse rsp = client.execute(req, accessToken);
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(rsp.getBody());
            JsonNode resultNode = rootNode.get("result");
            dingTalkId = resultNode.get("userid").asText();
        } catch (Exception e) {
            log.error("获取userid：" + userId + "的钉钉ID失败", e);
        }
        return dingTalkId;
    }

    /**
     * @description: 获取用户信息
     * @author: fu
     * @date: 2024/8/22 15:14
     * @param: [userId]
     * @return: java.lang.String
     **/
    private SysUser userPhoneNumber(Long userId) {
        LambdaQueryWrapper<SysUser> phoneQuery = Wrappers.lambdaQuery();
        phoneQuery.select(SysUser::getUserId, SysUser::getPhonenumber, SysUser::getUserName, SysUser::getNickName,
                        SysUser::getAvatar, SysUser::getSex, SysUser::getDeptId, SysUser::getTenantId)
                .eq(SysUser::getUserId, userId);
        return sysUserMapper.selectOne(phoneQuery);
    }

    @Async// 异步发送
    public void sendDingTalkDailyReport(PmWorkReport workReport, List<PmWorkContent> workContents) {
        String userName = workReport.getCreateBy();
        log.info(userName + "的工作报告开始发送钉钉-----------------------------------");
        try {
            String ccToStr = workReport.getCcTo();
            List<String> ccTo = new ArrayList<>();
            if (StringUtils.isNotBlank(ccToStr)) {
                String[] items = ccToStr.split(",");
                List<Long> userIds = new ArrayList<>();
                for (String item : items) {
                    long number = Long.parseLong(item.trim());
                    userIds.add(number);
                }
                for (Long userId : userIds) {
                    String dingTalkUserId = getDingTalkUserId(userId);
                    ccTo.add(dingTalkUserId);
                }
            }
            String reportCoordinateWork = workReport.getCoordinateWork();
            String reportTomorrowPlan = workReport.getTomorrowPlan();
            String coordinateWork1 = "-";
            String tomorrowPlan1 = "-";

            if (reportCoordinateWork != null && reportCoordinateWork != "") {
                coordinateWork1 = reportCoordinateWork;
            }
            if (reportTomorrowPlan != null && reportTomorrowPlan != "") {
                tomorrowPlan1 = reportTomorrowPlan;
            }

            StringBuilder contentBuilder = new StringBuilder();
            for (PmWorkContent content : workContents) {
                String projectName = content.getProjectName();
                BigDecimal workTime = content.getWorkTime();
                String workContent = content.getWorkContent();
                StringBuilder markdown = new StringBuilder();
                markdown.append("#### ").append(projectName).append(" ").append(workTime).append("h\n\n");
                markdown.append(workContent).append("\n");
                contentBuilder.append(markdown).append("\n\n");
            }
            String completedWork = contentBuilder.toString();
            DingTalkClient client = new DefaultDingTalkClient(dingTalkConstant.DING_TALK_CREATE_DAILY_REPORT_URL);
            OapiReportCreateRequest req = new OapiReportCreateRequest();
            OapiReportCreateRequest.OapiCreateReportParam obj1 = new OapiReportCreateRequest.OapiCreateReportParam();
            List<OapiReportCreateRequest.OapiReportContentVo> list3 = new ArrayList<>();
            OapiReportCreateRequest.OapiReportContentVo completedWorkD = new OapiReportCreateRequest.OapiReportContentVo();
            completedWorkD.setSort(0L);
            completedWorkD.setType(1L);
            completedWorkD.setContentType(dingTalkConstant.DING_TALK_DAILY_REPORT_CONTENT_TYPE);
            completedWorkD.setContent(completedWork);
            completedWorkD.setKey(dingTalkConstant.DING_TALK_DAILY_REPORT_COMPLETED_WORK);
            list3.add(completedWorkD);
            OapiReportCreateRequest.OapiReportContentVo tomorrowPlan = new OapiReportCreateRequest.OapiReportContentVo();
            tomorrowPlan.setSort(1L);
            tomorrowPlan.setType(1L);
            tomorrowPlan.setContentType(dingTalkConstant.DING_TALK_DAILY_REPORT_CONTENT_TYPE);
            tomorrowPlan.setContent(tomorrowPlan1);
            tomorrowPlan.setKey(dingTalkConstant.DING_TALK_DAILY_REPORT_TOMORROW_PLAN);
            list3.add(tomorrowPlan);
            OapiReportCreateRequest.OapiReportContentVo coordinateWork = new OapiReportCreateRequest.OapiReportContentVo();
            coordinateWork.setSort(2L);
            coordinateWork.setType(1L);
            coordinateWork.setContentType(dingTalkConstant.DING_TALK_DAILY_REPORT_CONTENT_TYPE);
            coordinateWork.setContent(coordinateWork1);
            coordinateWork.setKey(dingTalkConstant.DING_TALK_DAILY_REPORT_COORDINATE_WORK);
            list3.add(coordinateWork);
            obj1.setContents(list3);
            if (!ccTo.isEmpty()) {
                obj1.setToUserids(ccTo);
            }
            obj1.setTemplateId(dingTalkConstant.DING_TALK_DAILY_REPORT_TEMPLATE_ID);
            obj1.setToChat(dingTalkConstant.DING_TALK_DAILY_REPORT_TO_CHAT);
            obj1.setDdFrom(dingTalkConstant.DING_TALK_CORP_ID);
            obj1.setUserid(getDingTalkUserId(workReport.getSubmitterId()));
            // obj1.setToChat(true);
            //发送到群，群id
            // obj1.setToCids(dingTalkConstant.DING_TALK_DAILY_REPORT_TO_CIDS);
            req.setCreateReportParam(obj1);
            OapiReportCreateResponse rsp = client.execute(req, getDingTalkToken());
            if (rsp.isSuccess()) {
                log.info(userName + "的钉钉报告发送成功");
            } else {
                log.error(userName + "的钉钉报告发送失败： " + rsp.getErrmsg());
            }
        } catch (Exception e) {
            log.error(userName + "的钉钉报告发送消息时发生异常", e);
        }
        log.info(userName + "的工作报告发送钉钉结束-----------------------------------");
    }


    //@Async
    @Async
    public void sendAsyncMessage(PmWorkReport newReport) {
        String username = newReport.getCreateBy();
        Long submitterId = newReport.getSubmitterId();
        log.info(username + "的工作报告开始发送消息中心-----------------------------------");
        List<Long> userId = new ArrayList<>();
        if (!newReport.getCcTo().isEmpty()) {
            userId = Optional.of(newReport.getCcTo())
                    .map(ccTo -> Arrays.stream(ccTo.split(","))
                            .map(Long::parseLong)
                            .collect(Collectors.toList()))
                    .orElse(Collections.emptyList());
        } else {
            log.info(newReport.getCreateBy() + "的报告：" + newReport.getId() + "，抄送人为空，无需发送消息中心");
            return;
        }
        log.info("本次需要发送userId集合{}", userId);

        LambdaQueryWrapper<SysUser> nickNameQuery = Wrappers.lambdaQuery();
        nickNameQuery.select(SysUser::getNickName)
                .eq(SysUser::getUserId, submitterId);
        SysUser nickName = sysUserMapper.selectOne(nickNameQuery);

        MceRequestVO mceRequestVO = new MceRequestVO();
        mceRequestVO.setInfoTitle(INFO_TITLE);
        mceRequestVO.setInfoContent(nickName.getNickName() + INFO_CONTENT);
        mceRequestVO.setInfoType(String.valueOf(INFO_TYPE));
        mceRequestVO.setId(newReport.getId());
        mceRequestVO.setInfoTypeName(INFO_TITLE);
        mceRequestVO.setUserName(username);
        mceRequestVO.setRealName(nickName.getNickName());
        mceRequestVO.setTenantId(newReport.getTenantId());

        if (!userId.isEmpty()) {
            mceRequestVO.setUserIds(userId);
        }
        try {
            // 推送消息中心
            ApiResult<Void> voidApiResult = remoteMceService.addMceReceive(mceRequestVO);

            if (voidApiResult.isSuccess()) {
                log.info("报告消息发送成功！");
            } else {
                log.error("报告消息发送失败！");
            }
        } catch (Exception e) {
            log.error("报告发送消息时发生异常", e);
        }
        log.info(username + "的工作报告发送消息中心完成-----------------------------------");
    }

}

