package com.kingdee.eas.custom.sendmessage.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.ctrl.swing.StringUtils;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.metadata.entity.FilterInfo;
import com.kingdee.bos.metadata.entity.FilterItemInfo;
import com.kingdee.bos.metadata.entity.SelectorItemCollection;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.logs.IMessageLogs;
import com.kingdee.eas.custom.logs.MessageLogsFactory;
import com.kingdee.eas.custom.logs.MessageLogsInfo;
import com.kingdee.eas.custom.logs.app.SendStatusEnum;
import com.kingdee.eas.hr.ats.AtsUtil;
import com.kingdee.shr.base.syssetting.exception.SHRWebException;
import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
import com.kingdee.shr.certificationservice.*;
import com.kingdee.util.NumericExceptionSubItem;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author qingwu
 * @date 2024/11/19
 * @apiNote
 */
public class SendMessageUtils {
    private static Logger logger = Logger.getLogger(SendMessageUtils.class);
    private static Properties propt = new Properties();
    public  SendMessageUtils() throws BOSException {
        propt = GetMessageConfig.getProp();
    }


    /**
     * 发送消息
     *
     * @throws SHRWebException
     */
    public static void sendMessage(Context ctx, String billId) throws ShrWebBizException, BOSException, EASBizException {
        propt = GetMessageConfig.getProp();
        MessageLogsInfo messageLogsInfo = new MessageLogsInfo();
        IMessageLogs iMessageLogs = MessageLogsFactory.getLocalInstance(ctx);
        //成功条数
        int seccuss = 0;
        //失败条数
        int error = 0;
        try {
            Set<String> setBillId = AtsUtil.toSet(billId);
            //总条数
            messageLogsInfo.setCount(setBillId.size());
            //hr单据证明
            IHRCertificationBill ihrCertificationBill = HRCertificationBillFactory.getLocalInstance(ctx);
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("*");
            sic.add("person.name");
            sic.add("person.number");
            sic.add("person.id");
            sic.add("certificationTemplet.name");
            sic.add("certificationTemplet.number");
            sic.add("certificationTemplet.id");
            sic.add("certificationTemplet.certificationBillType.name");
            sic.add("certificationTemplet.certificationBillType.number");
            sic.add("certificationTemplet.certificationBillType.id");
            sic.add("certificationTemplet.templateId");
            FilterInfo filterInfo = new FilterInfo();
            filterInfo.getFilterItems().add(new FilterItemInfo("id", setBillId, CompareType.INCLUDE));
            EntityViewInfo entityViewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
            HRCertificationBillCollection hrCertificationBillCollection = ihrCertificationBill.getHRCertificationBillCollection(entityViewInfo);
            for (int i = 0; i < hrCertificationBillCollection.size(); i++) {
                HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i);
                PersonInfo person = hrCertificationBillInfo.getPerson();
                //手机号
                String callPhone = hrCertificationBillInfo.getCallPhone();
                //messageLogsInfo
                messageLogsInfo.setBillNo(hrCertificationBillInfo.getNumber());
                //证明模板
                CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet();
                String templateName = certificationTemplet.getName();
                String templateId = (String) certificationTemplet.get("templateId");
                if (StringUtils.isEmpty(templateId)) {
                    throw new ShrWebBizException(templateName + "模板的消息id为空，请问维护！！");
                }
                //证明模板
                HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType();
                //模版名称
                messageLogsInfo.setReserved1(templateName);
                messageLogsInfo.setReserved2(certificationBillType.getName());

                String md5Sign = null;
                //过滤封装手机号
                //Map<String, Set> phoneMap = disposeCollFillterPhone(hrCertificationBillCollection, messageLogsInfo);
                //密钥
                String appSecret = propt.getProperty("appSecret");
                //uuid
                String uuid = UUID.randomUUID().toString();
                System.out.println("uuid---" + uuid);
                //应用类型
                String appType = propt.getProperty("appType");
                //应用id
                String appId = propt.getProperty("appId");
                //url
                String url = propt.getProperty("url");
                String signName = propt.getProperty("signName");
                logger.error("url---" + url);
                //时间戳
                Date date = new Date();
                String time = String.valueOf(date.getTime());
                messageLogsInfo.setTime(date);
                logger.error("time---" + time);
                //参数
                JSONObject params = new JSONObject();
                params.put("appId", appId);
                params.put("templateId", templateId);
                params.put("signName", signName);
                //批量发送才需要这个参数
                params.put("phone", callPhone);
//                params.put("phone", "18692279043");
                params.put("appId", appId);
                //消息模板
                Map<String, String> resultMap = SaveFileForDisk.getPDFInfo(ctx, hrCertificationBillInfo);
                if(resultMap.isEmpty()) {
                    throw new EASBizException(new NumericExceptionSubItem("001","证件pdf文件为空"));
                }
                String urlPath = resultMap.get("urlPath");
                messageLogsInfo.setIsVaild(true);
                messageLogsInfo.setFileName(resultMap.get("fileName"));
                messageLogsInfo.setUrldir(resultMap.get("dirName"));
                messageLogsInfo.setUrlPath(urlPath);
                messageLogsInfo.setNCell(callPhone);
                //参数
                HashMap<String, Object> paraMap = new HashMap<>();
                paraMap.put("callPhone", callPhone);
                paraMap.put("urlPath", urlPath);
                paraMap.put("personInfo", person);
                LinkedHashMap<String, String> param = getTemplate(ctx, templateId, paraMap, messageLogsInfo);
                params.put("params", param);
                //请求参数
                JSONObject jsonObject = new JSONObject();
                //jsonObject.put("params", params.toString());
                jsonObject.put("time", time);
                jsonObject.put("uuid", uuid);
                jsonObject.put("phones", callPhone);
                md5Sign = md5Sign(appSecret, url, params, appType, time, uuid, jsonObject);
                jsonObject.put("md5Sign", md5Sign);
                jsonObject.put("resultMap", resultMap);
                messageLogsInfo.setRequestParams(resultMap.get("urlPath"));
                messageLogsInfo.setRequestParams(jsonObject.toString());
                logger.error("md5Sign---" + md5Sign);
                logger.error("params---" + params);
                Response resultResponse = sendMeesage(params, appType, appId, uuid, md5Sign, time);
                String body = resultResponse.body().string();
                logger.error("body---" + body);
                JSONObject result = JSONObject.parseObject(body);
                String code = result.get("code").toString();
                if (!code.equals("200")) {
                    error++;
                    messageLogsInfo.setStatus(SendStatusEnum.fail);
                } else {
                    seccuss++;
                    messageLogsInfo.setStatus(SendStatusEnum.succeed);
                    JSONObject dataObj = result.getJSONObject("data");
                    String sendRecordId = dataObj.getString("sendRecordId");
                    String sendStatus = dataObj.getString("sendStatus");
                    messageLogsInfo.setSourceBillId(sendRecordId);
                    messageLogsInfo.setSourceFunction(sendStatus);

                }
                messageLogsInfo.setIsVaild(true);
                //返回结果
                messageLogsInfo.setResult(body);
                messageLogsInfo.setSuccessNum(seccuss);
                messageLogsInfo.setFailNum(error);
                iMessageLogs.save(messageLogsInfo);

                IHRCertificationBill cartIns = HRCertificationBillFactory.getLocalInstance(ctx);
                HRCertificationBillInfo certInfo = cartIns.getHRCertificationBillInfo(new ObjectUuidPK(billId));
                certInfo.put("isSend" , true);
                SelectorItemCollection sc = new SelectorItemCollection();
                sc.add("isSend");
                cartIns.updatePartial(certInfo, sc);
            }

        } catch (Exception e) {
            error++;
            //返回结果
            messageLogsInfo.setFailNum(error);
            messageLogsInfo.setResult(e.getMessage());
            messageLogsInfo.setStatus(SendStatusEnum.fail);
            iMessageLogs.save(messageLogsInfo);
            e.printStackTrace();
            throw new ShrWebBizException(e);
        }
    }

    /***
     *  获取消息模板
     * @param ctx
     * @param templateId
     * @param paramMap 各种参数
     * @return
     */
    public static LinkedHashMap<String,String> getTemplate(Context ctx, String templateId, Map<String,Object> paramMap ,MessageLogsInfo messageLogsInfo) throws BOSException {
        TemplateStrategy strategy = TemplateStrategyFactory.getTemplateStrategy(templateId);
        return strategy.getTemplate(ctx, paramMap, messageLogsInfo);
    }

//    public static JSONObject getTemplate(Context ctx, String templateId, String phone, String urlPath, MessageLogsInfo messageLogsInfo) throws BOSException {
//        JSONObject param = new JSONObject();
//        IPersonContactMethod iPersonContactMethod = PersonContactMethodFactory.getLocalInstance(ctx);
//        PersonContactMethodInfo personContactMethodInfo = iPersonContactMethod
//                .getPersonContactMethodCollection("select * ,person.* where nCell = '" + phone + "'").get(0);
//        PersonInfo person = personContactMethodInfo.getPerson();
//        messageLogsInfo.setPerson(person);
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//        //SHR发送电子证明
//        if (templateId.equals("MSG_2411190001")) {
//            param.put("name", person.getName());
//            param.put("urlPath", urlPath);
//        }
//        //SHR发送离职通知
//        if (templateId.equals("MSG_2411200002")) {
//            IResignBizBillEntry iResignBizBillEntry = ResignBizBillEntryFactory.getLocalInstance(ctx);
//            ResignBizBillEntryInfo resignBizBillEntryInfo = iResignBizBillEntry
//                    .getResignBizBillEntryCollection("where person = '" + person.getId().toString() + "'").get(0);
//            Date bizDate = resignBizBillEntryInfo.getBizDate();
//            String lzDate = format.format(bizDate);
//            param.put("name", person.getName());
//            param.put("lzDate", lzDate);
//            param.put("urlPath", urlPath);
//        }
//        return param;
//    }


    /**
     * 通过模板id 分组过滤手机号以及校验是否有模板Id未维护
     *
     * @param hrCertificationBillCollection
     * @return
     */
    public Map disposeCollFillterPhone(HRCertificationBillCollection hrCertificationBillCollection, MessageLogsInfo messageLogsInfo) throws ShrWebBizException {
        Map<String, Set> certificationBillTypeMap = new HashMap<>();
        for (int i = 0; i < hrCertificationBillCollection.size(); i++) {
            HRCertificationBillInfo hrCertificationBillInfo = hrCertificationBillCollection.get(i);
            //手机号
            String callPhone = hrCertificationBillInfo.getCallPhone();
            //证明模板
            CertificationTempletInfo certificationTemplet = hrCertificationBillInfo.getCertificationTemplet();
            String templateName = certificationTemplet.getName();
            String templateId = (String) certificationTemplet.get("templateId");
            //证明模板
            HRCertificationBillTypeInfo certificationBillType = certificationTemplet.getCertificationBillType();
            //模版名称
            messageLogsInfo.setReserved1(templateName);
            messageLogsInfo.setReserved2(certificationBillType.getName());
            if (StringUtils.isEmpty(templateId)) {
                throw new ShrWebBizException(templateName + "模板的消息id为空，请问维护！！");
            }
            if (!certificationBillTypeMap.containsKey(templateId)) {
                certificationBillTypeMap.put(templateId, new HashSet<>());
            }
            certificationBillTypeMap.get(templateId).add(callPhone);
        }
        Map<String, Set> phoneMap = new HashMap<String, Set>();
        // 遍历输出结果map
        certificationBillTypeMap.forEach((templateId, callPhoneSet) -> {
            //多个人的手机号 用逗号隔开
            //String phones = deleteCharAt(callPhoneSet);
            phoneMap.put(templateId, callPhoneSet);
        });
        return phoneMap;
    }

    /**
     * 处理集合 封装数据
     *
     * @param set
     * @return
     */
    public String deleteCharAt(Set<String> set) {
        StringBuilder callPhoneBuilder = new StringBuilder();
        for (String phone : set) {
            callPhoneBuilder.append(phone).append(",");
        }
        callPhoneBuilder.deleteCharAt(callPhoneBuilder.lastIndexOf(","));
        return callPhoneBuilder.toString();
    }


    /**
     * 发送信息
     *
     * @param params
     * @param appType
     * @param appId
     * @param uuid
     * @param md5Sign
     * @throws IOException
     */
    private static Response sendMeesage(JSONObject params, String appType, String appId, String uuid, String md5Sign, String time) throws IOException {
        //发送请求
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, params.toString());
        Request request = new Request.Builder()
                //.url(propt.getProperty("sendMessageTaskUrl")) //批量发送消息
                .url(propt.getProperty("sendMessageUrl"))
                .post(body)
                //X-*-Sign 指定的算法，可选范围目前只有 md5，后续如有必要会增添其他算法
                .addHeader("X-message-Algorithm", "md5")
                //时间戳，请求时间，防止重放攻击，目前后台最多延时 15 分钟
                .addHeader("X-message-Time", time)
                //终端应用类型，比如小程序设置为 1、WEB 端设置为 2、APP 端设 置为 3，建议设置 2
                .addHeader("X-message-AppType", appType)
                //应用唯一标识，用于判断是那个应用调用消息中心
                .addHeader("X-message-AppID", appId)
                //随机码，防止重放攻击，延时时间之内不能重复，客户端可以采 用 UUID 生成
                .addHeader("X-message-Nonce", uuid)
                //签名 Sign，具体说明看下文
                //MD5( APPSECRET+路径+参数 +X-*-AppType +X-*-Time +X-*-Nonce )
                .addHeader("X-message-Sign", md5Sign)
                .addHeader("Content-Type", "application/json")
                .addHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0")
                .addHeader("Connection", "keep-alive")
                .addHeader("Accept", "*/*")
                .build();
        return client.newCall(request).execute();
    }

    /**
     * 获取 sign
     *
     * @param appSecret 密钥
     * @param url       url
     * @param params    参数
     * @param appType   类型 建议为2
     * @param appTime   时间戳
     * @param nonce     随机码
     * @return
     */
    public static String md5Sign(String appSecret, String url, Map params, String appType, String appTime, String nonce, JSONObject jsonObject) {
        //System.out.println(params.toString());
        String code = appSecret + url + params.toString() + appType + appTime + nonce;
        logger.error("code---" + code);
        jsonObject.put("code", code);
        return DigestUtils.md5Hex(code).toLowerCase();
    }


    /**
     * aes加密
     *
     * @param phone
     * @param appSecret
     * @return
     * @throws Exception
     */
    public static String encrypt(String phone, String appSecret) throws Exception {
        // 将自定义的字符串密钥转换为字节数组，注意要确保长度符合要求（AES 128位对应16字节等）
        byte[] keyBytes = appSecret.getBytes(StandardCharsets.UTF_8);
        // 如果密钥长度不符合要求，这里可以进行适当处理，比如截取或填充等，示例采用简单截取到16字节长度（仅针对128位AES示例）
        if (keyBytes.length > 16) {
            keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
        } else if (keyBytes.length < 16) {
            byte[] newKeyBytes = new byte[16];
            System.arraycopy(keyBytes, 0, newKeyBytes, 0, keyBytes.length);
            keyBytes = newKeyBytes;
        }

        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(phone.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
}
