@RestResource(urlMapping = '/NFM005/*')
global with sharing class NFM005Rest  implements Database.Batchable<sObject> {
    private final Id rowData_Id;
    private final Integer startIndex;
    private final Integer dataLength;
    private final Integer executeSize = 2000;
    global class SalesPricesRest {
        public SalesPrices SalesPrices;
    }
// Integer batchsize = 200;  考量する必要がないと思います。
    global class SalesPrices {
        public NFMUtil.Monitoring Monitoring;
        public NFM005Rest.SalesPrice[] SalesPrice;
    }
    global class SalesPrice {
        public String  PriceType;
        public String  SuppliersItemCode;
        public Decimal SalesPrice_x;
        public String  Currency_x;
        public String  ReportedDateTime;                       // 受信しない
        public String  EffectiveDateFrom;
        public String  EffectiveDateTo;
        public String  PurposeOfAdvice;
    }
    @HttpPost
    global static void execute() {

        // 取得接口传输内容
        String strData = RestContext.request.requestBody.toString();
        SalesPricesRest SalesPricesRest = (SalesPricesRest) JSON.deserializeStrict(strData, SalesPricesRest.class);
        if (SalesPricesRest == null || SalesPricesRest.SalesPrices == null
            || SalesPricesRest.SalesPrices.Monitoring == null) {
            return;
        }
        NFMUtil.Monitoring Monitoring = SalesPricesRest.SalesPrices.Monitoring;

        BatchIF_Log__c rowData = NFMUtil.saveRowData(Monitoring, 'NFM005', SalesPricesRest.SalesPrices.SalesPrice);
        if (SalesPricesRest.SalesPrices.SalesPrice == null || SalesPricesRest.SalesPrices.SalesPrice.size() == 0) {
            return;
        }
        NFM005Rest u = new NFM005Rest(rowData.Id, 0, SalesPricesRest.SalesPrices.SalesPrice.size());
        Database.executeBatch(u, 1);

        // JSONを戻す
        RestResponse res = RestContext.response;
        res.addHeader('Content-Type', 'application/json');
        res.statusCode = 200;
        //String jsonResponse = '{"status": "Success", "Message":'  + gedata + '}';
        String jsonResponse = '{"status": "Success", "Message":""}';
        res.responseBody = blob.valueOf(jsonResponse);
        return;
    }
    global NFM005Rest(Id rowData_Id, Integer startIndex, Integer dataLength) {
        this.rowData_Id = rowData_Id;
        this.startIndex = startIndex;
        this.dataLength = dataLength;
    }

    global Database.Querylocator start(Database.BatchableContext BC) {
        return Database.getQuerylocator([
                                            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 Id = :rowData_Id
                                        ]);
    }
    global void execute(Database.BatchableContext BC, List<BatchIF_Log__c> scope) {
        BatchIF_Log__c rowData = scope[0];
        String logstr = rowData.MessageGroupNumber__c + ' ' + startIndex + '/' + dataLength + ' start\n';
        BatchIF_Log__c iflog = new BatchIF_Log__c();
        iflog.Type__c = 'NFM005';
        iflog.MessageGroupNumber__c = rowData.MessageGroupNumber__c;
        iflog.Log__c = logstr;
        iflog.ErrorLog__c = '';
        insert iflog;
        String rowDataStr = NFMUtil.getRowDataStr(rowData);
        List<SalesPrice> salesPriceList2 = (List<SalesPrice>) JSON.deserialize(rowDataStr, List<SalesPrice>.class);
        if (salesPriceList2 == null || salesPriceList2.size() == 0) {
            return;
        }
        List<SalesPrice> salesPriceList = new List<SalesPrice>();
        List<String> productCodeList = new List<String>();
        for (Integer i = startIndex; (i < startIndex + executeSize && i < salesPriceList2.size()); i++) {
            salesPriceList.add(salesPriceList2.get(i));
            if (String.isBlank(salesPriceList2.get(i).SuppliersItemCode) == false) {
                productCodeList.add(salesPriceList2.get(i).SuppliersItemCode);
            }
        }
        logstr += 'Execute Record:' + salesPriceList.size() + '\n';

        Savepoint sp = Database.setSavepoint();
        try {
            // 更新対応配列とMapなどをセット
            Map<String, Product2> prdsMap = new Map<String, Product2>();
            for (Product2 prd : [select Id, ProductCode, ProductCode_Ext__c,
                                 Intra_Trade_List_RMB_1__c,
                                 Intra_Trade_List_RMB_Date1__c,
                                 Intra_Trade_List_RMB_End_Date1__c,
                                 Intra_Trade_List_RMB_2__c,
                                 Intra_Trade_List_RMB_Date2__c,
                                 Intra_Trade_List_RMB_End_Date2__c,
                                 Foreign_Trade_List_US_1__c,
                                 Foreign_Trade_List_US_Date1__c,
                                 Foreign_Trade_List_US_End_Date1__c,
                                 Foreign_Trade_List_US_2__c,
                                 Foreign_Trade_List_US_Date2__c,
                                 Foreign_Trade_List_US_End_Date2__c,
                                 Intra_Trade_List_US__c,
                                 Intra_Trade_List_US_Date__c,
                                 Intra_Trade_List_US_End_Date__c,
                                 Foreign_Trade_List_RMB__c,
                                 Foreign_Trade_List_RMB_Date__c,
                                 Foreign_Trade_List_RMB_End_Date__c
                                 from Product2
                                 where ProductCode_Ext__c in :productCodeList
                                 and Manual_Entry__c = False]
                ) {
                prdsMap.put(prd.ProductCode_Ext__c, prd);
            }

            // 更新対応配列をセット
            Map<String, Product2> prdUpdateMap = new Map<String, Product2>();
            for (NFM005Rest.SalesPrice SalesPrice : salesPriceList) {
                // deleteの場合、有効期限日に前日をセット
                if (SalesPrice.PurposeOfAdvice == '1') {
                    SalesPrice.EffectiveDateTo = NFMUtil.formatDate2Str(Date.today().addDays(-1));
                }

                // 必須項目がない場合、処理と飛ばす
                if (SalesPrice.SuppliersItemCode == null || SalesPrice.SuppliersItemCode == '') {
                    iflog.ErrorLog__c += 'SuppliersItemCode is required\n';
                    continue;
                }
                if (SalesPrice.PriceType == null || SalesPrice.PriceType == '') {
                    iflog.ErrorLog__c += '[' + SalesPrice.SuppliersItemCode + ']PriceType is required\n';
                    continue;
                }
                if (SalesPrice.SalesPrice_x == null) {
                    iflog.ErrorLog__c += '[' + SalesPrice.SuppliersItemCode + ']SalesPrice is required\n';
                    continue;
                }
                if (SalesPrice.Currency_x == null || SalesPrice.Currency_x == '') {
                    iflog.ErrorLog__c += '[' + SalesPrice.SuppliersItemCode + ']Currency is required\n';
                    continue;
                }
                if (SalesPrice.EffectiveDateFrom == null || SalesPrice.EffectiveDateFrom == '') {
                    iflog.ErrorLog__c += '[' + SalesPrice.SuppliersItemCode + ']EffectiveDateFrom is required\n';
                    continue;
                }
                if (SalesPrice.EffectiveDateTo == null || SalesPrice.EffectiveDateTo == '') {
                    iflog.ErrorLog__c += '[' + SalesPrice.SuppliersItemCode + ']EffectiveDateTo is required\n';
                    continue;
                }

                Product2 prd = prdsMap.get(SalesPrice.SuppliersItemCode);
                if (prd == null) {
                    // 更新対象商品がない場合
                    iflog.ErrorLog__c += 'Product[' + SalesPrice.SuppliersItemCode + ']NotExist\n';
                    continue;
                }

                // 項目転送のセット
                prd.ProductCode = SalesPrice.SuppliersItemCode;
                if (prdUpdateMap.get(prd.ProductCode) == null) {
                    prdUpdateMap.put(prd.ProductCode, prd);
                    logstr += SalesPrice.SuppliersItemCode + ' ';
                } else {
                    prd = prdUpdateMap.get(prd.ProductCode);
                }
                Date dateFrom = NFMUtil.parseStr2Date(SalesPrice.EffectiveDateFrom, false);
                Date dateTo = NFMUtil.parseStr2Date(SalesPrice.EffectiveDateTo, true);
                if (SalesPrice.PriceType == 'OCM-001S' && SalesPrice.Currency_x == 'RMB') {
                    if (prd.Intra_Trade_List_RMB_1__c == null || prd.Intra_Trade_List_RMB_End_Date1__c < Date.today() || prd.Intra_Trade_List_RMB_Date1__c == dateFrom) {
                        prd.Intra_Trade_List_RMB_1__c          = SalesPrice.SalesPrice_x;
                        prd.Intra_Trade_List_RMB_Date1__c      = dateFrom;
                        prd.Intra_Trade_List_RMB_End_Date1__c  = dateTo;
                    } else if (prd.Intra_Trade_List_RMB_2__c == null || prd.Intra_Trade_List_RMB_End_Date2__c < Date.today() || prd.Intra_Trade_List_RMB_Date2__c == dateFrom) {
                        prd.Intra_Trade_List_RMB_2__c          = SalesPrice.SalesPrice_x;
                        prd.Intra_Trade_List_RMB_Date2__c      = dateFrom;
                        prd.Intra_Trade_List_RMB_End_Date2__c  = dateTo;
                    } else if (prd.Intra_Trade_List_RMB_Date1__c < prd.Intra_Trade_List_RMB_Date2__c) {
                        prd.Intra_Trade_List_RMB_1__c          = SalesPrice.SalesPrice_x;
                        prd.Intra_Trade_List_RMB_Date1__c      = dateFrom;
                        prd.Intra_Trade_List_RMB_End_Date1__c  = dateTo;
                    } else {
                        prd.Intra_Trade_List_RMB_2__c          = SalesPrice.SalesPrice_x;
                        prd.Intra_Trade_List_RMB_Date2__c      = dateFrom;
                        prd.Intra_Trade_List_RMB_End_Date2__c  = dateTo;
                    }
                } else if (SalesPrice.PriceType == 'OHC-001S' && SalesPrice.Currency_x == 'USD') {
                    if (prd.Foreign_Trade_List_US_1__c == null || prd.Foreign_Trade_List_US_End_Date1__c < Date.today() || prd.Foreign_Trade_List_US_Date1__c == dateFrom) {
                        prd.Foreign_Trade_List_US_1__c         = SalesPrice.SalesPrice_x;
                        prd.Foreign_Trade_List_US_Date1__c     = dateFrom;
                        prd.Foreign_Trade_List_US_End_Date1__c = dateTo;
                    } else if (prd.Foreign_Trade_List_US_2__c == null || prd.Foreign_Trade_List_US_End_Date2__c < Date.today() || prd.Foreign_Trade_List_US_Date2__c == dateFrom) {
                        prd.Foreign_Trade_List_US_2__c         = SalesPrice.SalesPrice_x;
                        prd.Foreign_Trade_List_US_Date2__c     = dateFrom;
                        prd.Foreign_Trade_List_US_End_Date2__c = dateTo;
                    } else if (prd.Foreign_Trade_List_US_Date1__c < prd.Foreign_Trade_List_US_Date2__c) {
                        prd.Foreign_Trade_List_US_1__c         = SalesPrice.SalesPrice_x;
                        prd.Foreign_Trade_List_US_Date1__c     = dateFrom;
                        prd.Foreign_Trade_List_US_End_Date1__c = dateTo;
                    } else {
                        prd.Foreign_Trade_List_US_2__c         = SalesPrice.SalesPrice_x;
                        prd.Foreign_Trade_List_US_Date2__c     = dateFrom;
                        prd.Foreign_Trade_List_US_End_Date2__c = dateTo;
                    }
                } else if (SalesPrice.PriceType == 'OCM-001S' && SalesPrice.Currency_x == 'USD') {
                    prd.Intra_Trade_List_US__c             = SalesPrice.SalesPrice_x;
                    prd.Intra_Trade_List_US_Date__c        = dateFrom;
                    prd.Intra_Trade_List_US_End_Date__c    = dateTo;
                } else if (SalesPrice.PriceType == 'OHC-001S' && SalesPrice.Currency_x == 'RMB') {
                    prd.Foreign_Trade_List_RMB__c          = SalesPrice.SalesPrice_x;
                    prd.Foreign_Trade_List_RMB_Date__c     = dateFrom;
                    prd.Foreign_Trade_List_RMB_End_Date__c = dateTo;
                }
            }
            List<Product2> prdList = prdUpdateMap.values();
            if (prdList.size() > 0) {
                StaticParameter.EscapeSyncProduct2Trigger = true;
                update prdList;
            }
            logstr += '\nend';
        } catch (Exception ex) {
            // エラーが発生した場合
            Database.rollback(sp);
            System.debug(Logginglevel.ERROR, 'NFM005_' + rowData.MessageGroupNumber__c + ':' + ex.getMessage());
            System.debug(Logginglevel.ERROR, 'NFM005_' + rowData.MessageGroupNumber__c + ':' + ex.getStackTraceString());
            logstr += '\n' + ex.getMessage();
            iflog.ErrorLog__c = ex.getMessage() + '\n' + ex.getStackTraceString() + '\n' + iflog.ErrorLog__c;
        }
        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) + ' ...';
        }
        update iflog;
    }

    global void finish(Database.BatchableContext BC) {
        if (startIndex + executeSize < dataLength) {
            NFM005Rest u = new NFM005Rest(rowData_Id, startIndex + executeSize, dataLength);
            Database.executeBatch(u, 1);
        }
    }
}