package com.malk.kabeiyi.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.malk.core.McProject;
import com.malk.kabeiyi.service.KabeiyiService;
import com.malk.kabeiyi.util.RecognizeAllText;
import com.malk.kabeiyi.util.U8Util;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McException;
import com.malk.server.common.McR;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.aliwork.YDClient;
import com.malk.service.aliwork.YDService;
import com.malk.service.dingtalk.DDClient;
import com.malk.service.dingtalk.DDClient_Workflow;
import com.malk.utils.UtilHttp;
import com.malk.utils.UtilMap;
import com.malk.utils.UtilToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class KabeiyiServiceImpl implements KabeiyiService {
    @Autowired
    private DDClient_Workflow ddClient_workflow;

    @Autowired
    private DDClient ddClient;

    @Autowired
    private YDService ydService;

    @Autowired
    private YDClient ydClient;

    @Autowired
    private YDConf ydConf;

    @Autowired
    private DDConf ddConf;

    @Value("${tcdingtalk.appKey}")
    private String appKey;

    @Value("${tcdingtalk.appSecret}")
    private String appSecret;

    @Value("${aliwork.accessKeyId}")
    private String accessKeyId;

    @Value("${aliwork.accessKeySecret}")
    private String accessKeySecret;

    @Value("${ocr.filePath}")
    private String filePath;

    @Value("${u8.fromAccount}")
    private String fromAccount;

    @Value("${u8.toAccount}")
    private String toAccount;

    @Value("${u8.appKey}")
    private String u8AppKey;

    @Value("${u8.appSecret}")
    private String u8AppSecret;

    //审批实例url前缀（卡倍亿）
    private static final String PROC_INST_PREFIX_URL = "https://aflow.dingtalk.com/dingtalk/web/query/pchomepage.htm?from=oflow&op=true&corpid=dingc3a744cb591a7346f2c783f7214b6d69#/plainapproval?procInstId=";

    //宜搭-关联数据（卡倍亿）
    private static final String RELATION = "FORM-230C40137ED94524B4D4C94F8B23A8D2F8PF";

    //审批实例url前缀（特充）
    private static final String PROC_INST_PREFIX_URL2 = "https://aflow.dingtalk.com/dingtalk/web/query/pchomepage.htm?from=oflow&op=true&corpid=ding3ea249a3b5b466d0f2c783f7214b6d69#/plainapproval?procInstId=";

    //宜搭-关联数据（特充）
    private static final String RELATION2 = "FORM-51E17EFB52C14C9CB9E00168FED2BC18LQ6H";

    //问题整改表
    private static final String QUESTION = "FORM-89F515967FF94C62A9031F28EF6000B1YV5Q";

    //问题整改表流程code
    private static final String QUESTION_PROC_CODE = "TPROC--DP5660A1LEXNP1S37P7KU9GCHD5U3HB6C360M5";

    //审核表
    private static final String CHECK = "FORM-F4ED246EADD8427381BC13C4F0FEF7FDYMKJ";

    //审核表流程code
    private static final String CHECK_PROC_CODE = "TPROC--4XC66Y61XWWNZNJKBZD4VAB5BQAJ2YANX160M5";

    //审核计划
    private static final String CHECK_PLAN = "FORM-A9A7991EEB7D41FDAADADB9B1E1750FE0K5K";

    //产品实发
    private static final String PRODUCT_REAL = "FORM-809458EB6D524CF5AE1A91A3492D8B1BZIMN";

    //内部交易客户
    private static final String INTERNAL_CUSTOMER = "FORM-14782CE27EA54D2C94CC5BEF90554E5ALYP7";

    //内部工厂
    private static final String INTERNAL_FACTORY = "FORM-6CD7A1EDE1134AC8B2EE833769595C2EIWQ6";

     //关联表单（卡倍亿）
    private static final Map<String,String> SCHEMA_MAP = new HashMap<>();
    static{
        SCHEMA_MAP.put("工厂用章流程","1.1、工厂用章流程(除采购营销人事)");
        SCHEMA_MAP.put("中心用章流程","1.2、中心用章流程（除采购营销人事）");
        SCHEMA_MAP.put("人事专用用章审批流程","1.3、人事专用用章审批流程");
        SCHEMA_MAP.put("商务部用章申请流程","1.4、商务部用章申请流程");
        SCHEMA_MAP.put("办公用品采购申请流程","4.3、办公用品采购申请流程");

        //需传其他值
        //对方单位名称 收入或支出 金额 备注
        SCHEMA_MAP.put("信息化建设用章流程","1.7、信息化建设用章流程");
        //合同说明 采购物品类型
        SCHEMA_MAP.put("技术中心请购审批流程","4.10、技术中心请购审批流程");
        //合同总金额 合同说明
        SCHEMA_MAP.put("设备备品备件采购合同审批流程","4.1b、设备备品备件采购合同审批流程");
        SCHEMA_MAP.put("其他物品采购合同流程","4.2b、其他物品采购合同流程");
        SCHEMA_MAP.put("设备采购合同审批流程","4.5c、设备采购合同审批流程");
        SCHEMA_MAP.put("原材料采购合同审批流程","4.9b、原材料采购合同审批流程");
        SCHEMA_MAP.put("墨西哥采购合同审批流程","4.13b、墨西哥采购合同审批流程");
    }

    //关联表单（特充）
    private static final Map<String,String> SCHEMA_MAP2 = new HashMap<>();
    static{
        //需传其他值
        //对方单位名称 收入或支出 金额 备注
        SCHEMA_MAP2.put("特充用章流程","1.2、特充用章流程（除采购营销人事）");

        //合同总金额 合同说明
        SCHEMA_MAP2.put("设备备品备件采购合同审批流程","4.1b、设备备品备件采购合同审批流程");
        SCHEMA_MAP2.put("其他物品采购合同流程","4.2b、其他物品采购合同流程");
        SCHEMA_MAP2.put("母排设备采购合同审批流程","4.5c、母排设备采购合同审批流程");
        SCHEMA_MAP2.put("双铝设备采购合同审批流程","4.6c、双铝设备采购合同审批流程");

        //合同总金额
        SCHEMA_MAP2.put("原材料采购合同审批流程","4.9b、原材料采购合同审批流程");

        //文件类别 对方单位名称 收入或支出 金额 用印文件名称 文件份数 加盖何种印章 备注
        SCHEMA_MAP2.put("信息化建设用章流程","1.7、信息化建设用章流程");
    }

    @Override
    public McR addPayment(Map map) {
        try {
            String tradeid = U8Util.getTradeid();

            map.put("tradeid",tradeid);


            U8Util.sendPost(map,"https://api.yonyouup.com/api/voucher/add","voucher");

        }catch (Exception e) {
            return McR.errorUnknown(e.getMessage());
        }

        return McR.success();
    }

    @Override
    public McR pushProcInstToYD(Map map) {
        MDC.put("MDC_KEY_PID","1002");

        //审批实例
        String procInstId = String.valueOf(map.get("procInstId"));
        //获取审批实例信息
        Map processInstance = ddClient_workflow.getProcessInstanceId(ddClient.getAccessToken(), procInstId);
        if (Objects.nonNull(processInstance)){
            Map formData = new HashMap<>();
            String title = String.valueOf(processInstance.get("title"));
            String type = "";
            List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
            for (String key : SCHEMA_MAP.keySet()) {
                if (title.contains(key)){
                    type = SCHEMA_MAP.get(key);
                    switch (type){
                        case "1.7、信息化建设用章流程" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                String value = String.valueOf(formComponentValue.get("value")).equals("null") ? "" : String.valueOf(formComponentValue.get("value"));
                                switch (name){
                                    case "对方单位名称" : formData.put("textField_lygzlf3j",value);break;
                                    case "收入或支出" : formData.put("textField_lygzlf3k",value);break;
                                    case "金额" : formData.put("textField_lygzlf3l",value);break;
                                    case "备注" : formData.put("textField_lygzlf3m",value);break;
                                }
                            }
                            break;
                        case "4.1b、设备备品备件采购合同审批流程" :
                        case "4.2b、其他物品采购合同流程" :
                        case "4.5c、设备采购合同审批流程" :
                        case "4.9b、原材料采购合同审批流程" :
                        case "4.13b、墨西哥采购合同审批流程" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                switch (name){
                                    case "合同总金额" : formData.put("numberField_lyf81587",formComponentValue.get("value"));break;
                                    case "合同说明" :
                                        if (Objects.nonNull(formComponentValue.get("value"))){
                                            formData.put("textField_lyf81588",formComponentValue.get("value"));
                                        }
                                        break;
                                }
                            }
                            break;
                        case "4.10、技术中心请购审批流程" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                switch (name){
                                    case "采购物品类型" : formData.put("textField_lyibvb98",formComponentValue.get("value"));break;
                                    case "合同说明" :
                                        if (Objects.nonNull(formComponentValue.get("value"))){
                                            formData.put("textField_lyf81588",formComponentValue.get("value"));
                                        }
                                        break;
                                }
                            }
                            break;
                        default:
                            break;
                    }

                    formData.put("textField_lyf8157x",title);
                    formData.put("selectField_lyf81580",type);

                    Map condition = new HashMap<>();
                    condition.put("textField_lyf81581",PROC_INST_PREFIX_URL + procInstId);
                    //同步到宜搭
                    ydService.upsertFormData(RELATION,condition,formData,null);

                    break;
                }
            }
            return McR.success();
        }

        return McR.errorParam("审批实例不存在！");
    }

    @Override
    public McR pushProcInstToYD2(Map map) {
        MDC.put("MDC_KEY_PID","1003");

        //审批实例
        String procInstId = String.valueOf(map.get("procInstId"));
        //获取审批实例信息
        Map processInstance = ddClient_workflow.getProcessInstanceId(getTcAccessToken(), procInstId);
        if (Objects.nonNull(processInstance)){
            Map formData = new HashMap<>();
            String title = String.valueOf(processInstance.get("title"));
            String type = "";
            List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
            for (String key : SCHEMA_MAP2.keySet()) {
                if (title.contains(key)){
                    type = SCHEMA_MAP2.get(key);
                    switch (type){
                        case "1.7、信息化建设用章流程" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                Object value = formComponentValue.get("value");
                                switch (name){
                                    case "文件类别" : formData.put("textField_lymfq9oa",value);break;
                                    case "对方单位名称" : formData.put("textField_lygzlf3j",value);break;
                                    case "收入或支出" : formData.put("textField_lygzlf3k",value);break;
                                    case "金额（元）" : formData.put("textField_lygzlf3l",value);break;
                                    case "用印文件名称" : formData.put("textField_lymfq9oc",value);break;
                                    case "文件份数" : formData.put("numberField_lymfq9od",value);break;
                                    case "加盖何种印章" : formData.put("textField_lymfq9oe",value);break;
                                    case "备注" : formData.put("textField_lygzlf3m",value);break;
                                }
                            }
                            break;

                        case "4.1b、设备备品备件采购合同审批流程" :
                        case "4.2b、其他物品采购合同流程" :
                        case "4.5c、母排设备采购合同审批流程" :
                        case "4.6c、双铝设备采购合同审批流程" :
                        case "4.9b、原材料采购合同审批流程" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                switch (name){
                                    case "合同总金额（元）":
                                    case "合同总金额" : formData.put("numberField_lyf81587",formComponentValue.get("value"));break;
                                    case "合同说明" :
                                        if (Objects.nonNull(formComponentValue.get("value"))){
                                            formData.put("textField_lyf81588",formComponentValue.get("value"));
                                        }
                                        break;
                                }
                            }
                            break;
                        case "1.2、特充用章流程（除采购营销人事）" :
                            for (Map formComponentValue : formComponentValues) {
                                String name = String.valueOf(formComponentValue.get("name"));
                                String value = String.valueOf(formComponentValue.get("value")).equals("null") ? "" : String.valueOf(formComponentValue.get("value"));
                                switch (name){
                                    case "对方单位名称" : formData.put("textField_lygzlf3j",value);break;
                                    case "收入或支出" : formData.put("textField_lygzlf3k",value);break;
                                    case "金额（元）" : formData.put("textField_lygzlf3l",value);break;
                                    case "备注" : formData.put("textField_lygzlf3m",value);break;
                                }
                            }
                            break;
                        default:
                            break;
                    }

                    formData.put("textField_lyf8157x",title);
                    formData.put("selectField_lyf81580",type);

                    Map condition = new HashMap<>();
                    condition.put("textField_lyf81581",PROC_INST_PREFIX_URL2 + procInstId);


                    //同步到宜搭
                    ydService.upsertFormData(RELATION2,condition,formData,null);

                    break;
                }
            }
            return McR.success();
        }

        return McR.errorParam("审批实例不存在！");
    }

    @Override
    public McR addQuestionApproval(Map map) {
        MDC.put("MDC_KEY_PID","1009");

        if (Objects.isNull(map.get("formInstId"))){
            return McR.errorParam("formInstId不能为空！");
        }
        String formInstId = map.get("formInstId").toString();

        DDR_New ddrNew = ydClient.queryData(YDParam.builder()
                .formInstId(formInstId)
                .build(), YDConf.FORM_QUERY.retrieve_id);
        Map formData = ddrNew.getFormData();

        List<String> reviewerUserIds = (List<String>) formData.get("employeeField_m061zye5_id");//审核人
        String area = formData.get("selectField_m0w4kilf").toString();
        List<Map> details = (List<Map>) formData.get("tableField_m0kqtqoy");
        String[] yida = McProject.getYida("1009");
        for (Map detail : details) {
            String result = detail.get("radioField_m0nm3des").toString();
            if ("NG".equals(result)){
                //发起问题整改审批
                Map question = new HashMap();
                question.put("textField_m061zye8",detail.get("textField_m0on13ob"));//审核项目
                question.put("textareaField_m061zye9",detail.get("textField_m0kqtqoz"));//审核方法和标准
                question.put("attachmentField_m061zyep",detail.get("attachmentField_m061zyep"));//问题证据
                question.put("textareaField_m063drgz",detail.get("textareaField_m063drgz"));//问题描述
                question.put("dateField_m061zyev",detail.get("dateField_m061zyev"));//整改截止时间
                question.put("employeeField_m10dns9c",detail.get("employeeField_m10d5uqj_id"));//部门经理
                question.put("selectField_m0w4kilf",area);//审核区域

                Map<String,Object> body = new HashMap<>();
                body.put("appType",yida[0]);
                body.put("systemToken",yida[1]);
                body.put("userId",reviewerUserIds.get(0));
                body.put("formUuid",QUESTION);
                body.put("processCode",QUESTION_PROC_CODE);
                body.put("formDataJson", JSONObject.toJSONString(question));

                UtilHttp.doPost("https://api.dingtalk.com/v1.0/yida/processes/instances/start", ddClient.initTokenHeader(), null, body, DDR_New.class);

            }
        }
        return McR.success();
    }

    @Override
    public McR ocr(String downloadUrl,String name,String type) {
        MDC.put("MDC_KEY_PID","1020");

        //下载宜搭附件
        try {
            String[] yida = McProject.getYida("1020");
            downloadFile(downloadUrl,filePath + name,yida[0],yida[1]);
            log.info("文件下载成功!");
        } catch (IOException e) {
            e.printStackTrace();
            log.info("文件下载失败:{}" + e.getMessage());
        }
        //ocr识别
        try {
            String content = RecognizeAllText.recognizeText(filePath + name, type, accessKeyId, accessKeySecret);
            return McR.success(content);
        }catch (Exception e) {
            e.printStackTrace();
            log.info("识别失败:{}" + e.getMessage());
        }
        return McR.errorUnknown("识别失败！");
    }

    public void downloadFile(String fileURL, String savePath,String appType,String systemToken) throws IOException {
        //若是宜搭附件url 则需获得附件临时免登地址
        Map<String,Object> param = new HashMap<>();
        param.put("systemToken",systemToken);
        param.put("userId",ddConf.getOperator());
        param.put("fileUrl",fileURL);
        fileURL = ((DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v1.0/yida/apps/temporaryUrls/" + appType, ddClient.initTokenHeader(), param, DDR_New.class)).getResult().toString();

        URL url = new URL(fileURL);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        int responseCode = httpConn.getResponseCode();

        // 检查HTTP响应代码是否为200
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream inputStream = httpConn.getInputStream();
            FileOutputStream outputStream = new FileOutputStream(savePath);

            byte[] buffer = new byte[4096];
            int bytesRead = -1;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.close();
            inputStream.close();
        } else {
            System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
        }
        httpConn.disconnect();
    }

    @Override
    public McR addPlanApproval(Map map) {
        MDC.put("MDC_KEY_PID","1009");

        if (Objects.isNull(map.get("formInstId"))){
            return McR.errorParam("formInstId不能为空！");
        }
        String formInstId = map.get("formInstId").toString();

        DDR_New ddrNew = ydClient.queryData(YDParam.builder()
                .formInstId(formInstId)
                .build(), YDConf.FORM_QUERY.retrieve_id);
        //计划制定人
        Map originator = ddrNew.getOriginator();
        String planUserId = originator.get("userId").toString();

        Map formData = ddrNew.getFormData();
        //审核人
        List<String> reviewerUserIds = (List<String>) formData.get("employeeField_m061zye5_id");
        //频次
        String frequency = formData.get("selectField_m0koxj7g").toString();
        //下次自动发起审核日期
        long nextTime = (long) formData.get("dateField_m0nbpasq");
        Date nextDate = new Date(nextTime);

        //上次自动发起审核日期
        Date lastTime = nextDate;
        //审核截至日期
        Date endDate = new Date();
        switch (frequency){
            case "每周":
                endDate = DateUtils.addDays(nextDate, 6);
                nextDate = DateUtils.addDays(nextDate, 7);
                break;
            case "每两周":
                endDate = DateUtils.addDays(nextDate, 13);
                nextDate = DateUtils.addDays(nextDate, 14);
                break;
            case "每月":
                endDate = DateUtils.addDays(DateUtils.addMonths(nextDate, 1), -1);
                nextDate = DateUtils.addMonths(nextDate, 1);
                break;
            case "每季度":
                endDate = DateUtils.addDays(DateUtils.addMonths(nextDate, 3),-1);
                nextDate = DateUtils.addMonths(nextDate, 3);
                break;
            case "一次":
                endDate = new Date((long)formData.get("dateField_m0oqbh48"));
                nextDate = null;
                break;
            default:break;
        }
        //获取所有子表明细（大于50条）
        List<Map> details = getInnerTable(CHECK_PLAN,formInstId,"tableField_m0kqtqoy",1,50);
        formData.put("tableField_m0kqtqoy",details);
        //每个审批人发起审批
        for (String reviewerUserId : reviewerUserIds) {
            //根据userId获取部门id
            Map body = new HashMap<>();
            body.put("userid", reviewerUserId);

            DDR_New ddrNew1 = (DDR_New) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/v2/department/listparentbyuser", null, ddClient.initTokenParams(), body, DDR_New.class);
            Map result = (Map) ddrNew1.getResult();
            List<Map> parentList = (List<Map>) result.get("parent_list");
            List<Long> parentDeptIdList = (List<Long>) parentList.get(0).get("parent_dept_id_list");
            String deptId = parentDeptIdList.get(0) + "";
            formData.put("departmentSelectField_m0c3qbjn", new String[]{deptId});
            formData.put("dateField_m061zye7", endDate.getTime());
            formData.put("employeeField_m061zye5",new String[]{reviewerUserId});
            //发起审批
            String[] yida = McProject.getYida("1009");
            Map<String,Object> body2 = new HashMap<>();

            body2.put("appType",yida[0]);
            body2.put("systemToken",yida[1]);
            body2.put("userId",planUserId);
            body2.put("formUuid",CHECK);
            body2.put("processCode",CHECK_PROC_CODE);
            body2.put("formDataJson", JSONObject.toJSONString(formData));

            UtilHttp.doPost("https://api.dingtalk.com/v1.0/yida/processes/instances/start", ddClient.initTokenHeader(), null, body2, DDR_New.class);
        }

        //更新审核计划下次发起审批时间及上次发起审批时间
        formData.put("dateField_m0nbpasw", lastTime);
        formData.put("dateField_m0nbpasq", nextDate);
        formData.put("employeeField_m061zye5",reviewerUserIds);
        ydClient.operateData(YDParam.builder()
                        .formInstId(formInstId)
                        .updateFormDataJson(JSON.toJSONString(formData))
                        .build(), YDConf.FORM_OPERATION.update);

        return McR.success();
    }

    private List<Map> getInnerTable(String formUuid, String formInstId, String tableField, int pageNumber, int pageSize) {
        List<Map> details = new ArrayList<>();
        DDR_New ddrNew = new DDR_New();

        do {
            ddrNew = ydClient.queryData(YDParam.builder()
                    .formUuid(formUuid)
                    .formInstId(formInstId)
                    .tableFieldId(tableField)
                    .pageNumber(pageNumber)
                    .pageSize(pageSize)
                    .build(), YDConf.FORM_QUERY.retrieve_details);
            details.addAll((List<Map>)ddrNew.getData());
            pageNumber++;
        }while (ddrNew.getTotalCount() > pageSize * ddrNew.getPageNumber());

        return details;
    }

    @Override
    @Async
    public McR getDeliveryInfo() {
        //现在时间戳
        long beginTime = System.currentTimeMillis();

        MDC.put("MDC_KEY_PID","1019");

        //内部交易客户
        DDR_New ddrNew = ydClient.queryData(YDParam.builder()
                .formUuid(INTERNAL_CUSTOMER)
                .build(), YDConf.FORM_QUERY.retrieve_list);
        List<Map> data = (List<Map>) ddrNew.getData();

        Set<String> cusCodes = new HashSet<>();
        for (Map map : data) {
            Map formData = (Map) map.get("formData");
            cusCodes.add(getString(formData.get("textField_m1g1tp7i")));
        }

        //数据源对应工厂
        Map<Integer,String> factory = new HashMap<>();
        DDR_New ddrNew2 = ydClient.queryData(YDParam.builder()
                .formUuid(INTERNAL_FACTORY)
                .build(), YDConf.FORM_QUERY.retrieve_list);
        List<Map> data2 = (List<Map>) ddrNew2.getData();
        for (Map map : data2) {
            Map formData = (Map) map.get("formData");
            int dqNumber = (int) formData.get("numberField_m1fvucmc");//数据源序号
            String factoryName = getString(formData.get("textField_m1fvucmd"));//工厂名称
            factory.put(dqNumber,factoryName);
        }
        List<Map> errorList = new ArrayList<>();

        //同步当月内的数据 upsert
        DateTime dateTime = DateUtil.offsetDay(new Date(), -1);
        String yesterday = dateTime.toString("yyyy-MM-dd");

        DateTime beginOfMonth = DateUtil.beginOfMonth(DateUtil.lastMonth());
        String beginOfMonthString = beginOfMonth.toString("yyyy-MM-dd");

/*        String beginOfMonthString = "2024-10-09";

        String yesterday = "2024-10-09";*/
        for (Integer dsSequence : factory.keySet()) {
            List<String> errorCodes = new ArrayList<>();

            Map<String,Object> param = new HashMap<>();
            param.put("from_account",fromAccount);
            param.put("to_account",toAccount);
            param.put("app_key", u8AppKey);
            param.put("token", getU8Token());
            param.put("page_index", 1);
            param.put("rows_per_page", 50);
            param.put("ds_sequence", dsSequence);
            param.put("date_begin", beginOfMonthString);
            param.put("date_end", yesterday);

            Map<String, Object> map = get("https://api.yonyouup.com/api/consignmentlist/batch_get", param, null);
            if (!getString(map.get("errcode")).equals("0")){
                log.error("获取发货单列表失败:{}",map.get("errmsg"));
                continue;
            }
            if (!map.get("page_count").equals("1")){
                Integer rowCount = Integer.valueOf(map.get("row_count").toString());
                param.put("rows_per_page",rowCount);
                map = get("https://api.yonyouup.com/api/consignmentlist/batch_get", param, null);
            }
            List<Map> consignmentList = (List<Map>) map.get("consignmentlist");

            for (Map consignment : consignmentList) {
                //查询单个发货单详情
                String id = getString(consignment.get("code"));

                Map<String, Object> param2 = new HashMap<>();
                param2.put("from_account", fromAccount);
                param2.put("to_account", fromAccount);
                param2.put("app_key", u8AppKey);
                param2.put("token", getU8Token());
                param2.put("id", id);
                param2.put("ds_sequence", dsSequence);

                Map<String, Object> map2 = new HashMap<>();

                int i1 =1 ;
                boolean flag1 = false;
                while (i1<=5 && !flag1) {
                    try {
                        map2 = get("https://api.yonyouup.com/api/consignment/get", param2, null);
                        flag1 = true;
                    } catch (Exception e) {
                        log.error("获取发货单详情失败:{}, 重试次数:{}",e.getMessage(),i1);
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException ex) {
                            throw new RuntimeException(ex);
                        }
                        i1++;
                    }
                }
                if (i1 > 5){
                    log.error("获取发货单详情失败");
                    errorCodes.add(id);
                    continue;
                }


                Map consignment2 = (Map) map2.get("consignment");

                Map formData = new HashMap();
                //若为内部交易客户，则不同步
                String cusCode = getString(consignment2.get("custcode"));
                if (cusCodes.contains(cusCode)){
                    continue;
                }

                formData.put("textField_m18nvp7y",getString(consignment2.get("cusname")));//客户名称
                formData.put("textField_m219zpzf",getString(consignment2.get("cusabbname")));//客户码
                formData.put("textField_m18qfuiz",getString(consignment2.get("operation_type")));//操作类型
                formData.put("textField_m18qfuj0",getString(consignment2.get("saletypename")));//销售类型
                formData.put("textField_m18nvp87",getString(consignment2.get("code")));//发货单code
                formData.put("dateField_m18nvp7x",DateUtil.parseDate(getString(consignment.get("date"))).getTime());//发货日期
                formData.put("textField_m18nvp7z",getString(consignment2.get("deptname")));//部门
                formData.put("textField_m18nvp81",getString(consignment2.get("maker")));//生产员
                formData.put("textField_m18nvp80",getString(consignment2.get("verifier")));//质检员
                formData.put("numberField_m18wkih7",dsSequence);//数据源序号
                formData.put("textField_m1er3scl",factory.get(dsSequence));//工厂名称

                List<Map> entry = (List<Map>) consignment2.get("entry");
                List<Map> collect = entry.stream().map(item -> {
                    Map detail = new HashMap();
                    detail.put("textField_m18nvp8c", getString(item.get("socode")));//销售订单号
                    detail.put("textField_m18nvp8d", getString(item.get("warehouse_name")));//仓库名称
                    detail.put("textField_m18nvp8e", getString(item.get("inventory_name")));//存货名称
                    detail.put("textField_m22mkwzk", getString(item.get("define29")));//客户存货码
                    detail.put("textField_m18nvp8f", getString(item.get("cinvm_unit")));//单位
                    detail.put("numberField_m18nvp8h", getString(item.get("quantity")));//发货长度
                    detail.put("numberField_m18nvp8j", getString(item.get("price")));//未税单价
                    detail.put("numberField_m18nvp8l", getString(item.get("money")));//未税总价
                    detail.put("numberField_m18nvp8k", getString(item.get("taxprice")));//含税单价
                    detail.put("numberField_m18nvp8m", getString(item.get("sum")));//含税总价
                    detail.put("numberField_m18nvp8n", getString(item.get("taxrate")));//税率
                    detail.put("numberField_m18nvp8o", getString(item.get("tax")));//总税价
                    detail.put("dateField_m18yzlob", DateUtil.parseDate(getString(consignment.get("date"))).getTime());//发货日期
                    detail.put("textField_m18z3yn8", getString(consignment2.get("cusname")));//客户名称
                    detail.put("textField_m219zpzg", getString(item.get("free1")));//客户码
                    detail.put("textField_m21b1bhg", getString(item.get("free2")));//产品颜色

                    detail.put("textField_m1odluob", factory.get(dsSequence));//工厂名称

                    return detail;
                }).collect(Collectors.toList());

                formData.put("tableField_m18nvp82",collect);//发货明细
                int i=1;
                boolean flag = false;
                while (i<=5 && !flag){
                    try{
                        List<Map> jsonString = new ArrayList<>();
                        jsonString.add(UtilMap.map("key, value, type, operator, componentName", "textField_m18nvp87",getString(consignment2.get("code")),"TEXT","eq","TextField"));
                        jsonString.add(UtilMap.map("key, value, type, operator, componentName", "numberField_m18wkih7",new int[]{dsSequence,dsSequence},"DOUBLE","between","NumberField"));

                        String searchCondition = JSONObject.toJSONString(jsonString);

                        ydClient.operateData(YDParam.builder()
                                .formUuid(PRODUCT_REAL)
//                                .searchCondition(JSON.toJSONString(UtilMap.map("textField_m18nvp87, numberField_m18wkih7",getString(consignment2.get("code")),dsSequence)))//模糊查询
                                .searchCondition(searchCondition)//精准查询
                                .formDataJson(JSON.toJSONString(formData))
                                .build(), YDConf.FORM_OPERATION.upsert);
                        flag = true;
                    }catch (McException e){
                        if (e.getMessage().contains("The request has failed due to a temporary failure of the server.")){
                            log.error("upsert失败，尝试次数:{}",i);
                            i++;
                            try {
                                Thread.sleep(3000);
                            } catch (InterruptedException ex) {
                                throw new RuntimeException(ex);
                            }
                        }else {
                            log.error("upsert，失败原因:{}" , e.getMessage());
                            errorCodes.add(id);
                            flag = true;
                        }
                    }catch (Exception e){
                        log.error("发货单:{} 同步失败 失败原因:{}",getString(consignment2.get("code")) , e.getMessage());
                        errorCodes.add(id);
                        flag = true;
                    }
                }
                if (i>5){
                    errorCodes.add(id);
                    log.error("发货单:{} 同步失败 失败原因:{}",getString(consignment2.get("code")) , "重试次数过多");
                }
            }

            Map error = new HashMap();
            error.put("ds_sequence",dsSequence);
            error.put("error_count",errorCodes.size());
            //errorCodes逗号分隔
            error.put("error_codes",errorCodes.stream().collect(Collectors.joining(",")));
            errorList.add(error);

        }
        long endTime = System.currentTimeMillis();
        double time = (endTime - beginTime) / 1000.0;
        log.info("同步完成，耗时:{}秒", time);
        log.info("同步失败列表: {}", errorList);

        //记录失败日志
        Map<String,Object> formData = new HashMap<>();
        formData.put("dateField_m21oifwi",beginTime);
        formData.put("dateField_m21oifwp",endTime);
        formData.put("numberField_m21oifwo",time);
        //换行分隔errorList
        String errorStr = errorList.stream().map(item -> {
            String s = "数据源序号:" + item.get("ds_sequence") + ",错误数量:" + item.get("error_count") + ",发货单codes:" + item.get("error_codes");
            return s;
        }).collect(Collectors.joining("\n"));
        formData.put("textareaField_m21oifwj",errorStr);
        ydClient.operateData(YDParam.builder()
                .formUuid("FORM-F297D439FFF747ACB26DEA940850CD9B13LM")
                .formDataJson(JSON.toJSONString(formData))
                .build(), YDConf.FORM_OPERATION.create);
        return McR.success();
    }

    /**
     * 封装GET请求
     *
     * @param url    请求的URL
     * @param params 请求参数
     * @param headers 请求头
     * @return 响应内容
     */
    public static Map<String, Object> get(String url, Map<String, Object> params, Map<String, String> headers) {
        log.info("GET 请求url:{}, 请求参数:{}, 请求头:{}", url, params, headers);
        HttpRequest get = HttpUtil.createGet(url);
        if (params!= null){
            get.form(params);
        }

        if (headers!= null){
            get.addHeaders(headers);
        }
        HttpResponse response = get.execute();

        Map<String, Object> result = null;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            result = objectMapper.readValue(response.body(), new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        log.info("响应结果: {}", result);
        return result;
    }

    private String getU8Token(){
        String accessToken = UtilToken.get("u8-token");
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        } else {
            Map<String,Object> param = new HashMap<>();
            param.put("from_account", fromAccount);
            param.put("app_key", u8AppKey);
            param.put("app_secret", u8AppSecret);

            Map<String, Object> result = get("https://api.yonyouup.com/system/token", param, null);
            Map token = (Map) result.get("token");
            String id = token.get("id").toString();
            log.info("u响应token, {}", id);
            UtilToken.put("u8-token", id, (int) token.get("expiresIn") * 1000L);

            return id;
        }
    }


    private String getString(Object obj){
        return obj == null ? "" : obj.toString();
    }

    public String getTcAccessToken() {
        String accessToken = UtilToken.get("tc-invalid-token-dingtalk");
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        } else {
            Map param = new HashMap();
            param.put("appkey", appKey);
            param.put("appsecret", appSecret);
            DDR r = (DDR)UtilHttp.doGet("https://oapi.dingtalk.com/gettoken", param, DDR.class);
            log.info("特充响应token, {}", r.getAccessToken());
            accessToken = r.getAccessToken();
            UtilToken.put("tc-invalid-token-dingtalk", accessToken, (long)r.getExpiresIn() * 1000L);
            return accessToken;
        }
    }
}
