public with sharing class NFM501Controller implements Queueable {
    //先定义
    public class AllData {
        public String code;
        public QLMData data;
        public String msg;
    }
    public class QLMData {
        public String cursorMark;
        public ListItem[] list1;
    }
    public class ListItem {
        public String[] ZhaoBiaoUnit;
        public String infoId;
        //public String extractProjName;//
        public String infoTitle;
        public String keywords;
        public String biddingType;
        public String infoQianlimaUrl;
        public String[] ZhaoRelationWay;
        public String isElectronic;
        public String xmNumber;
        public String tenderEndTime;
        public String areaProvince;
        public String[] ZhongBiaoUnit;
        public String[] moreZhongBiaoUnit;// add 2021/12/03 fxk
        public String allKeywords;// add 2021/12/06 fxk 
        public String infoType;
        public String openBidingTime;
        public String[] AgentRelationWay;
        public String[] InfoFile;
        public AmountItem[] Budget;
        public String infoPublishTime;
        public String[] AgentRelationName;
        public String bidingEndTime;
        public AmountItem[] WinnerAmount;
        public String[] ZhongRelationWay;
        public String bidingAcquireTime;
        public String tenderBeginTime;
        public Target Target;
        public String areaCity;
        public String areaCountry;
        public String[] AgentUnit;
        public String projectId;
        public String[] ZhaoRelationName;
        public String[] ZhongRelationName;
        public String infoTypeSegment;
    }
    public class AmountItem {
        public String Amount;
        public String Unit;
    }

    public class Target {
        public String SumUnit;
        public String Sum;
        public TargetDetailsItem[] TargetDetails;
    }
    public class TargetDetailsItem {
        public String number1;
        public String priceUnit;
        public String tarKeyword;
        public String totalPrice;
        public String price;
        public String totalPriceUnit;
        public String name;
        public String model;
        public String brand;
        public String numberUnit;
    }

    public NFM501Controller() {

    }
    // 最大值为3，用来作为判断错误的条件（重发三次）
    public static Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);

    public void execute(QueueableContext context) {
        //1、检索IF转换表中，关于之前的cMark（游标）
        BatchIF_Transfer__c oldMark = [Select ID, Internal_Value__c FROM BatchIF_Transfer__c
                                       Where Table__c = 'QLMoldMark'];
        //检索rowData日志(当存在日志中的GroupNumber字段中的Mark与转换表存的Mark一致)
        List<BatchIF_Log__c> rowDataList =
            [select Id, Name, Log__c, ErrorLog__c, Log2__c, Log3__c, Log4__c,
             Log5__c, Log6__c, Log7__c, Log8__c, Log9__c, Log10__c, Log11__c,
             Log12__c, MessageGroupNumber__c from BatchIF_Log__c
             where RowDataFlg__c = true and MessageGroupNumber__c = :oldMark.Internal_Value__c ];
        System.debug('-------1-------' + rowDataList);
        //如果没有rowdata日志，则创建日志
        BatchIF_Log__c rowData = new BatchIF_Log__c();
        if (rowDataList == null || rowDataList.size() == 0) {
            rowData.Type__c = 'NFM501';
            rowData.RowDataFlg__c = true;
            rowData.MessageGroupNumber__c = oldMark.Internal_Value__c;
            insert rowData;
            System.debug('-------2-------');
            //如果只存在一个日志,将其第一个日志赋值给rowdata日志
        } else if (rowDataList.size() >= 1) {
            rowData = rowDataList[0];
            System.debug('-------3-------');
        }
        //如果存在两个日志，
        //else if(rowDataList.size() == 2){
        //     if(rowDataList[0].last_501__c){
        //         rowData =rowDataList[0];
        //     }else{
        //         rowData =rowDataList[1];
        //     }
        // }
        //创建一个iflog日志表，用来存报错信息
        BatchIF_Log__c iflog = new BatchIF_Log__c();
        iflog.Type__c = 'NFM501';
        iflog.RowDataFlg__c = false;
        iflog.MessageGroupNumber__c = oldMark.Internal_Value__c;
        iflog.Log__c = '';
        iflog.ErrorLog__c = '';
        insert iflog;
        NFM501Controller.sendRequest( rowData.id, iflog.id, false);

    }

    @future(callout = true)
    public static void sendRequest(String rowDataid, String iflogid, boolean Manual_execution501) {
        BatchIF_Log__c rowData = [select Id, Name, Log__c, ErrorLog__c, Log2__c, Log3__c, Log4__c,
                                  Log5__c, Log6__c, Log7__c, Log8__c, Log9__c, Log10__c, Log11__c,
                                  Log12__c, MessageGroupNumber__c, retry_cnt__c
                                  from BatchIF_Log__c where id = : rowDataid ];
        system.debug('-------4-------');
        BatchIF_Log__c iflog = [select Id, Name, Log__c, ErrorLog__c, Log2__c, Log3__c, Log4__c,
                                Log5__c, Log6__c, Log7__c, Log8__c, Log9__c, Log10__c, Log11__c,
                                Log12__c, MessageGroupNumber__c, retry_cnt__c
                                from BatchIF_Log__c where id = : iflogid ];
        // 由于检索出来的rowData和iflog为空，则进行一下判断
        iflog.Log__c = iflog.Log__c == null ? '' : iflog.Log__c;
        iflog.ErrorLog__c = iflog.ErrorLog__c == null ? '' : iflog.ErrorLog__c;
        rowData.Log__c = rowData.Log__c == null ? '' : rowData.Log__c;
        rowData.ErrorLog__c = rowData.ErrorLog__c == null ? '' : rowData.ErrorLog__c;
        System.debug('iflog:12345678' + iflog);
        // Savepoint sp = Database.setSavepoint();

        try {
            String token;
            Datetime oldTime;
            // aaaaaaaa 这里检索需要换行，否则一行看不见
            // 从转换表里检索token及其获取结束时间
            BatchIF_Transfer__c oldTimeTran = [Select ID, NFM501_Gain_End_Time__c
                                               FROM BatchIF_Transfer__c Where Table__c = 'NFM501GainEndTime'];
            BatchIF_Transfer__c tokenTran = [Select ID, NFM501_Token__c
                                             FROM BatchIF_Transfer__c Where Table__c = 'NFM501Token'];
            BatchIF_Transfer__c oldMark = [Select ID, Internal_Value__c
                                           FROM BatchIF_Transfer__c Where Table__c = 'QLMoldMark'];
            System.debug('oldTimeTran=' + oldTimeTran.NFM501_Gain_End_Time__c
                         + 'tokenTran=' + tokenTran.NFM501_Token__c);
            //1、 获取token（token每过两小时会失效重新获取，以下逻辑使token每30分钟自动获取一遍）:
            token = tokenTran.NFM501_Token__c;
            oldTime = oldTimeTran.NFM501_Gain_End_Time__c ;
            Long timeslot;
            Datetime newTime = System.now();
            // System.debug('++++1++++'+oldTime);
            // System.debug('++++2++++'+newTime);
            if (oldTime == null) {
                timeslot = 2800000;
            } else {
                timeslot = newTime.getTime() - oldTime.getTime();
            }
            System.debug('++++1++++' + token + '  : ' + timeslot);
            if (string.isblank(token) || timeslot > 1800000) {
                System.debug('++++2++++' + token + '  : ' + timeslot);
                NFMUtil.response response = NFMUtil.receiveToken();
                System.debug('++++response++++' + response);
                //判断rowdata中数据获取成功与否，如果失败重发三次，如果大于三次则手动操作
                if (String.isBlank(response.responseBody)) {
                    System.debug('response.responseBody:' + response.responseBody);
                    iflog.ErrorLog__c = '501token:' + response.status;
                    if (!Manual_execution501) {
                        NFM501Controller.againSendRequest(iflog, 'retry_cnt__c', rowData);
                    }
                    // aaaaaaaa 既然是token 抓取失败，那么这里就不应该更新
                    return;
                }
                //获取token
                token = response.responseBody;
                System.debug('-------6-------' + token);
                //获取结束时间
                oldTime = Datetime.now();
                // 为转换表中重新附上新值
                tokenTran.NFM501_Token__c = token;
                oldTimeTran.NFM501_Gain_End_Time__c = oldTime;

            }
            //替换获取到数据中的关键字
            NFMUtil.response response = NFMUtil.getQLMData(NFMUtil.NFM501_ENDPOINT
                                        + oldMark.Internal_Value__c + '/10', token);
            // aaaaaaaa 这里顺序错了，肯定是应该先判断是不是因为http 报错，然后才是千里马的code解析
            //http的报错处理（重发三遍）
            if (String.isBlank(response.responseBody)) {
                System.debug('-------7-------');
                // aaaaaaaa 报错原因写的不对
                iflog.ErrorLog__c = '501Http报错信息：' + response.status;
                if (!Manual_execution501) {
                    NFM501Controller.againSendRequest(iflog, 'retry_cnt__c', rowData);
                }
                update tokenTran;
                update oldTimeTran;
                return;
            }

            // aaaaaaaa 这里这个字段可以改名为NFM501Response 之类的，这样就有区分度了
            // 解析后的code报错处理
            String NFM501responseBody = response.responseBody;
            System.debug('-------------NFM501responseBody------------' + NFM501responseBody);
            NFM501responseBody = NFM501responseBody.replaceAll('"list"', '"list1"').replaceAll('"number":', '"number1":');
            AllData getQLMData =  (AllData) JSON.deserializeStrict(NFM501responseBody, AllData.class);
            System.debug('-------------8------------' + getQLMData);
            if (!getQLMData.code.equals('0')) {
                System.debug('-------99-------');
                iflog.ErrorLog__c = '501解析：' + getQLMData.msg ;
                if (!Manual_execution501) {
                    NFM501Controller.againSendRequest(iflog, 'retry_cnt__c', rowData);
                }
                update tokenTran;
                update oldTimeTran;
                return;
            }
            rowData = NFMUtil.QLMmakeRowData(NFM501responseBody, rowData);
            System.debug('======2221234======');

            update tokenTran;
            update oldTimeTran;
            String newMark = getQLMData.data.cursorMark;
            //4、新旧mark对比，如果不相等重新接收数据，并把新mark存入转换表中，之后更新；
            if (!newMark.equals(oldMark.Internal_Value__c)) {
                System.debug('1234567');
                oldMark.Internal_Value__c = newMark;
                update oldMark;
                if (!Test.isRunningTest()) {
                    System.enqueueJob(new NFM501FutureController(rowData.id));

                }
                NFM501Schedule2.assignOneMinute();
            } else if (newMark.equals(oldMark.Internal_Value__c) || Test.isRunningTest()) {
                // 之前数据抓取完毕后，过十分钟后，整体抓取503附件
                NFM503InfoFileSchedule.assignOneMinute();
                // 12点自动抓取招投标数据
                // NFM501Controller.TwoMarkEqualAgainSend();
            }

            rowData.retry_cnt__c = 0;
            if (System.Test.isRunningTest()) {
                throw new ControllerUtil.myException('aaa');
            }
        } catch (Exception ex) {
            // Database.rollback(sp);
            System.debug('rollback');
            // System.debug(Logginglevel.ERROR, 'QLMData_' + rowData.MessageGroupNumber__c + ':' + ex.getMessage());
            // System.debug(Logginglevel.ERROR, 'QLMData_' + rowData.MessageGroupNumber__c + ':' + ex.getStackTraceString());
            // logstr += '\n' + ex.getMessage();
            iflog.ErrorLog__c = '501抛出异常：' + ex.getMessage() + '\n'
                                + ex.getStackTraceString() + '\n' + iflog.ErrorLog__c;
            if (!Manual_execution501) {
                NFM501Controller.NFM501againSendExceptionRequest(iflog, 'retry_cnt__c', rowData, '501抛出异常：' +
                        ex.getMessage() + '\n' + ex.getStackTraceString()
                        + '\n' + rowData.ErrorLog__c +
                        '错误次数已经超过自动收信设定的最大次数，请手动收信');
            }
        }
        update rowData;
        System.debug('+++++++5+++++++' + rowData);
        System.debug('+++++++3+++++++' + iflog.Log__c);
        System.debug('+++++++2+++++++' + iflog.ErrorLog__c);
        //如果存入信息超出限制，用省略号代替
        if (iflog.Log__c.length() > 131072) {
            iflog.Log__c = iflog.Log__c.subString(0, 131065) + ' ...';
        }
        if (iflog.ErrorLog__c.length() > 32768) {
            iflog.ErrorLog__c = iflog.ErrorLog__c.subString(0, 32760) + ' ...';
        }
        upsert iflog;
    }
    public static void againSendRequest(BatchIF_Log__c iflog, String count, BatchIF_Log__c rowData ) {
        //判断rowdata中数据获取成功与否，如果失败重发三次，如果大于三次则手动操作
        System.debug('-------9-------');
        Integer rowDataStr = Integer.valueOf(rowData.get(count));
        rowDataStr = 0;
        if (rowDataStr == null) rowDataStr = 0;
        if (rowDataStr  < batch_retry_max_cnt) {
            rowDataStr++;
            NFM501Schedule2.assignOneMinute();
        }
        if (rowDataStr >= batch_retry_max_cnt) {
            iflog.ErrorLog__c += '错误次数已经超过自动收信设定的最大次数，请手动收信';
            rowData.ErrorLog__c += '错误次数已经超过自动收信设定的最大次数，请手动收信';
        }
        upsert rowData;
        upsert iflog;
        rowData.put(count, rowDataStr);
    }
    public static void againSendExceptionRequest(BatchIF_Log__c iflog, String count, BatchIF_Log__c rowData, String errorStr ) {
        //判断rowdata中数据获取成功与否，如果失败重发三次，如果大于三次则手动操作
        System.debug('=======9-------');
        Integer rowDataStr = Integer.valueOf(rowData.get(count));
        if (rowDataStr == null) {
            rowDataStr = 0;
        }
        if (rowDataStr  < batch_retry_max_cnt) {
            rowDataStr++;
            LogAutoSendSchedule.assignOneMinute();
        }
        if (rowDataStr >= batch_retry_max_cnt) {
            rowData.ErrorLog__c += errorStr;
        }
        rowData.put(count, rowDataStr);
    }
    public static void NFM501againSendExceptionRequest(BatchIF_Log__c iflog, String count, BatchIF_Log__c rowData, String errorStr ) {
        //判断rowdata中数据获取成功与否，如果失败重发三次，如果大于三次则手动操作
        System.debug('=======9-------');
        Integer rowDataStr = Integer.valueOf(rowData.get(count));
        if (rowDataStr == null) {
            rowDataStr = 0;
        }
        if (rowDataStr  < batch_retry_max_cnt) {
            rowDataStr++;
            NFM501Schedule2.assignOneMinute();
        }
        if (rowDataStr >= batch_retry_max_cnt) {
            rowData.ErrorLog__c += errorStr;
        }
        rowData.put(count, rowDataStr);
    }
    // 12点自动抓取招投标数据
    // public static void TwoMarkEqualAgainSend() {
    //     DateTime now = System.now();
    //     if (now.hour() < 12) {
    //          NFM501Schedule2.assignTwoMinute();
    //     }
    // }
    public static void test() {
        integer i = 0;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        
    }
}

//rowData中创建token ,时间字段的原因，
//

//把错误信息提出来做成公用方法
//
// // token = b.access_token;
// //解析从千里马数据库获取到的数据（解析成类形式）
// QLMData getQLMData =  (QLMData) JSON.deserializeStrict(responseBody2, QLMData.class);
// if (getQLMData == null ) {
//     return;
// }

// BatchIF_Log__c rowData = NFMUtil.QLMsaveRowData( 'QLMData', getQLMData);
// System.debug('----------1--------'+rowData);
// if (String.isBlank(rowData.Log__c) == false){
//     NFM501FutureController.execute('a001s000002LNiP');
// }

//将cursormark存在IF转换表中，循环与之前的mark做对比，知道现在的与前一个mark相同，这说明数据全部获取完成
//1、检索IF转换表中，关于之前的cMark
// BatchIF_Transfer__c oldMark = [Select ID, Internal_Value__c FROM BatchIF_Transfer__c Where Table__c = 'QLMoldMark'];
// //2、取新获取的cMark
// String newMark = getQLMData.cursorMark;
// //3、将数据存到日志中（）

// iflog1.Log__c = response2.getBody();
// insert iflog1;
// //4、新旧mark对比，如果不相等重新接收数据，并把新mark存入转换表中，之后更新；
// if(newMark != oldMark.Internal_Value__c){
//  System.enqueueJob(new NFM501Controller(token, oldTime));
//  oldMark.Internal_Value__c = newMark;
//  update oldMark;
// }


//       List<String> infourlList = new List<String>();
//       for(ListItem u : getQLMData.list1){
//  infourlList.add(u.infoQianlimaUrl);
// }
// //3、获取网页：记得使用1中获取的token，记得EndPoint 使用2中获取的网页
// Http http3 = new Http();
// HttpRequest req3 = new HttpRequest();
// req3.setHeader('Content-Type','application/x-www-form-urlencoded');
// req3.setHeader('open-authorization', 'Bearer'+token);
// req3.setTimeout(120000);
// req3.setEndpoint('http://cusdata.qianlima.com/test/v1/info/detailHtml?url='+infourlList);
// req3.setMethod('GET');

// HTTPResponse response3 = http3.send(req3);
// String responseBody3 = response3.getBody();
// //截切数据（使数据成为解析的格式）
// Integer start1 = responseBody3.indexOf('<!');
//       Integer theEnd1 = responseBody3.lastIndexOf('"},"msg');
//       responseBody3 = responseBody3.substring(start1,theEnd1);
//       System.debug('Body ' + responseBody3);
// System.debug('Status ' + response3.getStatus());
// System.debug('Status code ' + response3.getStatusCode());
// System.debug('----------3----------'+getQLMData );


// }

// }