@RestResource(urlMapping = '/NFM611/*')
global with sharing class NFM611Rest {
    public static final String LOG_TYPE = 'NFM611';

    global class GeData {
        public RepairOrderInfo repairOrderInfo;
        public QuotationInfo quotationInfo;
        public EquipReturnInfo equipReturnInfo;
        public LogisticsInfo logisticsInfo;
    }
    //报修单信息
    public class RepairOrderInfo {
        public Integer api_type; //同步信息类型
        public String repairOrderNo; //报修单号
        public String repairNo; //修理单号
    }
    //报价信息
    public class QuotationInfo {
        public String PlanQuotationDate; //计划报价日期
        public String ActualQuotationDate; //实际报价开始时间
        public String ActualQuotationEndTime; //实际报价结束时间
    }
    //设备归还信息
    public class EquipReturnInfo {
        public String engineerType; //人员角色
        public String PlanReturnDate; //计划归还日期
        public String ActualReturnStartTime; //实际归还开始时间
        public String ActualReturnDate; //实际归还结束时间
    }
    //物流信息
    public class LogisticsInfo {
        public String logisticsNo; //物流单号
        public String carrier; //承运商
        public String logisticsSendTime; //物流发送日期
        public String logisticsReceiveTime; //物流签收日期
        public String logisticsLatestStatus; //物流最新状态
    }

    @HttpPost
    global static void doPost() {

        // 取得接口传输内容
        String strData = RestContext.request.requestBody.toString();
        List < GeData > ges = (List < GeData > ) JSON.deserializeStrict(strData, List < GeData > .class);

        if (ges == null) {
            return;
        }

        BatchIF_Log__c iflog = new BatchIF_Log__c();
        iflog.Type__c = LOG_TYPE;
        iflog.ErrorLog__c = '';
        iflog.Log__c = 'callout start\n';

        BatchIF_Log__c rowData = NFMUtil.makeRowData(iflog, LOG_TYPE, ges);
        insert rowData;
        if (String.isBlank(rowData.Log__c) == false) {
            executefuture(rowData.Id);
        }
        // JSONを戻す
        RestResponse res = RestContext.response;
        res.addHeader('Content-Type', 'application/json');
        res.statusCode = 200;
        String jsonResponse = '{"status": "Success", "Message":"成功"}';
        res.responseBody = Blob.valueOf(jsonResponse);
        return;

    }

    @future(callout = true)
    global static void executefuture(String rowData_Id) {
        main(rowData_Id);
    }

    global static void main(String rowData_Id) {

        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 RowDataFlg__c = true and Id =: rowData_Id];

        String logstr = rowData.MessageGroupNumber__c + ' start\n';
        BatchIF_Log__c iflog = new BatchIF_Log__c();
        iflog.Type__c = LOG_TYPE;
        iflog.MessageGroupNumber__c = rowData.MessageGroupNumber__c;
        iflog.Log__c = logstr;
        iflog.ErrorLog__c = '';

        String rowDataStr = NFMUtil.getRowDataStr(rowData);

        List < GeData > itemMasterList = (List < GeData > ) JSON.deserialize(rowDataStr, List < GeData > .class);

        if (itemMasterList == null || itemMasterList.size() == 0) {
            return;
        }
        logstr += iflog.Log__c + '\nAllNumberOfRecord=' + itemMasterList.size() + ' ';
        Savepoint sp = Database.setSavepoint();

        try {

            Map < String, GeData > geDataMap = new Map < String, GeData > (); //key修理单号，value Gedatad对象
            for (GeData ged: itemMasterList) {
                String dataComplete = verify(ged);
                if (!String.isBlank(dataComplete)) {
                    logstr += dataComplete;
                    continue;
                }
                geDataMap.put(ged.repairOrderInfo.repairNo, ged);
            }
            if (geDataMap.size() > 0) {
                List < Repair__c > repairList = [select id,Name from Repair__c where Name in: geDataMap.keySet()];


                Map < String, Id > repairMap = new Map < String, Id > ();
                for (Repair__c r: repairList) {
                    repairMap.put(r.Name, r.Id);
                }

                logstr += iflog.Log__c + '\nUpdateNumberOfRecord=' + repairList.size() + ' ';
                List < Repair__c > updateList = new List < Repair__c > ();
                List<LogisticsInformation__c> upsertLogisticsInformationList = new List<LogisticsInformation__c>();
                Map < String, Map < String, Id >> logisticsInformationMap = getLogisticsInformationMap(geDataMap);
                
                for (String repairNo: geDataMap.keySet()) {

                    if (!repairMap.containsKey(repairNo)) {
                        logstr += repairNo + '修理单号不存在,此条数据跳过！';
                        continue;
                    }

                    GeData ged = geDataMap.get(repairNo);
                    Repair__c repair = new Repair__c();
                    repair.Id = repairMap.get(repairNo);
                    String logisticsType = '';
                    if (ged.repairOrderInfo.api_type == 1) {
                        repair.PlanQuotationTime__c = NFMUtil.parseStr2DateTime(ged.quotationInfo.PlanQuotationDate); //计划报价日期
                        repair.ActualQuotationStartTime__c = NFMUtil.parseStr2DateTime(ged.quotationInfo.ActualQuotationDate); //实际报价开始时间
                        repair.ActualQuotationEndTime__c = NFMUtil.parseStr2DateTime(ged.quotationInfo.ActualQuotationEndTime); //实际报价结束时间
                    } else if (ged.repairOrderInfo.api_type == 2) {
                        repair.PlanReturntime__c = NFMUtil.parseStr2DateTime(ged.EquipReturnInfo.PlanReturnDate); //计划归还日期
                        repair.ActualReturnStartTime__c = NFMUtil.parseStr2DateTime(ged.EquipReturnInfo.ActualReturnStartTime); //实际归还开始时间
                        repair.ActualReturnEndTime__c = NFMUtil.parseStr2DateTime(ged.EquipReturnInfo.ActualReturnDate); //实际归还结束时间
                    } else if (ged.repairOrderInfo.api_type == 3) {//送修物流信息
                        logisticsType = '送修物流';
                        repair.DeliveryLogisticsNo__c = ged.LogisticsInfo.logisticsNo; //送修物流单号
                        repair.LogisticsSendTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsSendTime); //送修物流发送日期
                        repair.LogisticsReceiveTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsReceiveTime); //送修物流签收日期
                    } else if (ged.repairOrderInfo.api_type == 4) {//归还物流信息
                        logisticsType = '归还物流';
                        repair.ReturnLogisticsNo__c = ged.LogisticsInfo.logisticsNo;
                        repair.ReturnLogisticsDeliveryTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsSendTime); //归还物流发送日期
                        repair.ReturnLogisticsSigningTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsReceiveTime); //归还物流签收日期
                    } else if (ged.repairOrderInfo.api_type == 5) {//返品物流信息
                        logisticsType = '返品物流';
                        repair.ReturnOrderSendTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsSendTime); //返品物流发送日期
                        repair.ReturnOrderReceiveTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsReceiveTime); //返品物流签收日期
                        repair.ReturnOrderNo__c = ged.LogisticsInfo.logisticsNo; //返品物流单号
                        repair.ReturnOrderLatestStatus__c = ged.LogisticsInfo.logisticsLatestStatus;

                    }
                    if (String.isNotBlank(logisticsType)) {
                        LogisticsInformation__c logisticsInformation = DataAssembly(ged,logisticsType,logisticsInformationMap,repairMap);
                        upsertLogisticsInformationList.add(logisticsInformation);
                    }
                    updateList.add(repair);
                }
                if (updateList.size() > 0) {
                    update updateList;
                }
                System.debug('upsertLogisticsInformationList--->'+upsertLogisticsInformationList);
                if (upsertLogisticsInformationList.size() > 0) {
                	upsert upsertLogisticsInformationList;
                }
                
            }
            logstr += ' end\n';
            rowData.retry_cnt__c = 0;
        } catch (Exception ex) {

            // Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);
            // エラーが発生した場合
            Database.rollback(sp);
            // logstr += '\n' + ex.getMessage();
            // iflog.ErrorLog__c = ex.getMessage() + '\n' + ex.getStackTraceString() + '\n' + iflog.ErrorLog__c;
            // if (rowData.retry_cnt__c == null) rowData.retry_cnt__c = 0;
            // if (rowData.retry_cnt__c < batch_retry_max_cnt) {
            //     rowData.retry_cnt__c++;
            //     LogAutoSendSchedule.assignOneMinute();
            // }
            // if (rowData.retry_cnt__c >= batch_retry_max_cnt) {
            //     rowData.ErrorLog__c = ex.getMessage() + '\n' + ex.getStackTraceString() + '\n' + rowData.ErrorLog__c + '错误次数已经超过自动收信设定的最大次数，请手动收信';
            // }
            rowData = NFMUtil.LogAutoSend(rowData, ex, null);
        }

        update rowData;
        iflog.Log__c = logstr;
        // 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) + ' ...';
        // }
        insert iflog;

    }

    private static String verify(GeData ged) {
        String result = '';
        if (ged.repairOrderInfo == null) {
            result += 'DataError: repairOrderInfo is null!\n';
        } else {
            String repairNo = ged.repairOrderInfo.repairNo;
            if (String.isBlank(repairNo)) {
                result += 'DataError:   repairNo is null!\n';
            }
            if (ged.repairOrderInfo.api_type == null) {
                result += 'DataError: [ ' + repairNo + ' ] api_type is null!\n';
            }
            if ((ged.repairOrderInfo.api_type == 3 || ged.repairOrderInfo.api_type == 4 || ged.repairOrderInfo.api_type == 5) &&
                String.isBlank(ged.LogisticsInfo.logisticsNo)) {
                result += 'DataError: [ ' + repairNo + ' ] logisticsNo is null!\n';

            }
            
        }

        return result;
    }
    /**
     * [查找修理下的物流信息]
     * @param  geDataMap [description]
     * @return           [修理 对应的 物流信息]
     */
    private static Map < String, Map < String, Id >> getLogisticsInformationMap(Map < String, GeData > geDataMap) {
        List < LogisticsInformation__c > logisticsInformationList = [Select Id, LogisticsNo__c, LogisticsRepair__r.Name FROM LogisticsInformation__c WHERE LogisticsRepair__r.Name IN: geDataMap.keySet()];
        Map < String, Map < String, Id >> result = new Map < String, Map < String, Id >> ();
        for (LogisticsInformation__c logistics: logisticsInformationList) {

            String repairName = logistics.LogisticsRepair__r.Name;
            String logisticsNo = logistics.LogisticsNo__c;
            Map < String, Id > logisticsMap = new Map < String, Id > ();

            if (result.containsKey(repairName)) {
                logisticsMap = result.get(repairName);
            }
            logisticsMap.put(logistics.LogisticsNo__c, logistics.Id);
            result.put(repairName, logisticsMap);

        }
        return result;
    }
    /**
     * [物流信息 数据拼装]
     * @param  ged                     [接口数据]
     * @param  logisticsType           [物流类型]
     * @param  logisticsInformationMap [修理对应 的物流信息]
     * @param  repairMap               [修理]
     * @return                         [物流信息]
     */
    public static LogisticsInformation__c DataAssembly(GeData ged, String logisticsType, Map < String, Map < String, Id >> logisticsInformationMap,Map < String, Id > repairMap) {

    	System.debug('logisticsInformationMap--->'+logisticsInformationMap);
        // 修理单号
        String repairNo = ged.repairOrderInfo.repairNo;
        Map < String, Id > logisticsMap = new Map < String, Id > ();
        if (logisticsInformationMap.containsKey(repairNo)) {
            logisticsMap = logisticsInformationMap.get(repairNo);
        }
        System.debug('logisticsMap--->'+logisticsMap);

        LogisticsInformation__c result = new LogisticsInformation__c();
        // 物流单号
        String logisticsNo = ged.LogisticsInfo.logisticsNo;
        System.debug('logisticsNo--->'+logisticsNo);
        result.Name = logisticsNo;
        result.Id = logisticsMap.containsKey(logisticsNo) ? logisticsMap.get(logisticsNo) : null;
        result.LogisticsNo__c = logisticsNo; //物流单号
        result.LogisticsCompany__c = ged.LogisticsInfo.carrier; //承运商
        result.LogisticsSendTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsSendTime); //物流发送日期
        result.LogisticsSignTime__c = NFMUtil.parseStr2DateTime(ged.LogisticsInfo.logisticsReceiveTime); //物流签收日期
        result.LogisticsLatestStatus__c = ged.LogisticsInfo.logisticsLatestStatus; //物流最新状态
        result.LogisticsType__c = logisticsType;//物流分类
        result.LogisticsRepair__c = repairMap.get(repairNo);//修理
        return result;
    }

}