@RestResource(urlMapping = '/SBGITMRestNew/*')
global with sharing class SBGITMRestNew {
    global class GeDatasRest {
        public GeDatas GeDatas;
    }

    global class GeDatas {
        public NFMUtil.Monitoring Monitoring;
        public SBGITMRestNew.GeData[] GeData;
    }
    global class GeData {
        public String  ProductCode;
        public String  ProductDescription;
        public String  ProductStatus;
        public String  EffectiveDateTo;
        public String  Other1;
        public String  Other2;
        public String  Other3;

        //20190717 SSBG_CBPR
        public String Exemption;//豁免标识
        public String IsRadiant;//辐射标识
        public String NMPAStatus;//首营物料状态
        public String StatusEffectiveDateFrom;//有效期开始日
        //20190717 SSBG_CBPR

        public String ZCHG_STATUS;//变更方式--1.新增;2.变更(不变更NMPAStatus与StatusEffectiveDateFrom)
        //3.首营物料状态变更(只更NMPAStatus与StatusEffectiveDateFrom);9.变更(ProductStatus__c)
        public String ECCODE;

        public String ProSerial; //辐射产品系列
    }

    @HttpPost
    global static void execute() {

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

        if (ges == null ) {
            return;
        }

        NFMUtil.Monitoring Monitoring = ges.GeDatas.Monitoring;
        if (Monitoring == null) {
            return;
        }

        BatchIF_Log__c rowData = NFMUtil.saveRowData(Monitoring, 'SBGITMRestNew', ges.GeDatas.GeData);
        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":'  + gedata + '}';
        String jsonResponse = '{"status": "Success", "Message":""}';
        res.responseBody = blob.valueOf(jsonResponse);
        return;
    }

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

    global static void main(String rowData_Id) {

        Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);
        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 = 'SBGITMRestNew';
        iflog.MessageGroupNumber__c = rowData.MessageGroupNumber__c;
        iflog.Log__c = logstr;
        iflog.ErrorLog__c = '';
        insert iflog;
        String rowDataStr = NFMUtil.getRowDataStr(rowData);
        List<GeData> itemMasterList = (List<GeData>) JSON.deserialize(rowDataStr, List<GeData>.class);
        if (itemMasterList == null || itemMasterList.size() == 0) {
            return;
        }


        Savepoint sp = Database.setSavepoint();
        try {
            // 更新対応配列とMapなどをセット
            List<String> productCodeList = new List<String>();
            for (GeData GeData : itemMasterList) {
                if (GeData.ProductCode == null || GeData.ProductCode == '') {
                    // 必須項目がない場合、処理と飛ばす
                    continue;
                }
                Pattern pattern = Pattern.compile('^[0-9]*$');  
                Matcher isNum = pattern.matcher(GeData.ProductCode); 
                if (isNum.matches()) {
                    GeData.ProductCode = GeData.ProductCode.leftPad(18, '0');
                }
                
                productCodeList.add(GeData.ProductCode);
            }
            List<Product2> prdList = [select Id,
                                      ProductCode,
                                      Description,
                                      ProductStatus__c,
                                      EffectiveDateTo__c,
                                      NMPAStatus_one__c, MaterialStatus_one_Start__c, MaterialStatus_one_End__c,
                                      NMPAStatus_two__c, MaterialStatus_two_Start__c, MaterialStatus_two_End__c
                                      from Product2
                                      where ProductModels__c = false and ProductCode in :productCodeList];
            Map<String, Product2> prdsMap = new Map<String, Product2>();
            for (Product2 prd : prdList) {
                prdsMap.put(prd.ProductCode, prd);
            }

            // 更新対応配列をセット
            prdList = new List<Product2>();
            Map<String, Product2> prdUpdateMap = new Map<String, Product2>();
            for (GeData GeData : itemMasterList) {
                if (GeData.ProductCode == null || GeData.ProductCode == '') {
                    // 必須項目がない場合、処理と飛ばす
                    iflog.ErrorLog__c += 'MaterialNumber is required\n';
                    continue;
                }

                if (String.isBlank(GeData.ProductDescription) && GeData.ZCHG_STATUS != '9') {
                    iflog.ErrorLog__c += 'Description is required:' + GeData.ProductCode  + ' \n';
                    continue;
                }

                Product2 prd = prdsMap.get(GeData.ProductCode);
                String prdName = null;

                if (prd == null && GeData.ZCHG_STATUS == '1' ) {
                    prd = new Product2();
                } else if (prd == null && GeData.ZCHG_STATUS != '1') {
                    iflog.ErrorLog__c += 'Product[' + GeData.ProductCode + ']NotExist\n';
                    continue;
                }

                // 項目転送のセット
                prd.ProductCode        = GeData.ProductCode;
                prd.IsActive = true;
                if (prdUpdateMap.get(prd.ProductCode) == null) {
                    prdList.add(prd);
                    prdUpdateMap.put(prd.ProductCode, prd);
                    //logstr += GeData.MaterialNumber + ' ';               // 価格表のところまとめてlogを出す
                } else {
                    prd = prdUpdateMap.get(prd.ProductCode);
                }

                if (GeData.ZCHG_STATUS == '9') {
                    if (GeData.ProductStatus != null) {
                        logstr += 'From SAP → '+GeData.ProductCode+'← 产品状态变更\n';
                        prd.ProductStatus__c = GeData.ProductStatus;
                    }
                    continue;
                }
                // 中文名称が転送してきた場合
                prdName = GeData.ProductDescription;
                if (prdName != null) {

                    if (GeData.ZCHG_STATUS == '1') {
                        logstr += 'From SPO → '+GeData.ProductCode+'← 产品新增\n';
                        prd = product2NMPAStatus(prd, GeData);
                    } else if (GeData.ZCHG_STATUS == '2') {
                        logstr += 'From SPO → '+GeData.ProductCode+'← 产品变更 非首营物料状态变更\n';
                        //prd = product2NMPAStatus(prd,GeData);
                    } else if (GeData.ZCHG_STATUS == '3') {
                        logstr += 'From SPO → '+GeData.ProductCode+'← 产品变更 只首营物料状态变更\n';
                        prd = product2NMPAStatus(prd, GeData);
                        continue;
                    }

                    prd.If_Exempt_Product__c = GeData.Exemption == '1' ? true : false;
                    if (GeData.IsRadiant == '1') {
                        prd.If_Radiation_Product__c = true;
                    } else {
                        prd.If_Radiation_Product__c = false;
                    }
                    prd.RadiationType__c = GeData.ProSerial;

                    // デフォルト値
                    prd.Name = prdName;
                    String alternative_Products = null;
                    String nDM_Model_No = null;
                    prd.Name = prdName.trim();

                    if (String.isBlank(GeData.ECCODE)) {
                        prd.Product_ECCode__c = GeData.ProductCode;
                        prd.Description =  GeData.ProductDescription ;
                    } else {
                        prd.Product_ECCode__c = GeData.ECCODE;
                        prd.Description = GeData.ECCODE + ':' + GeData.ProductDescription ;
                    }

                    if (GeData.ProductCode != null) {
                        prd.ProductCode = GeData.ProductCode;
                    }

                    if (GeData.ProductStatus != null) {
                        prd.ProductStatus__c = GeData.ProductStatus;
                    }
                    prd.EffectiveDateTo__c = NFMUtil.parseStr2Date('40001231', true);
                }
            }
            if (prdList.size() > 0) {
                logstr += 'Execute Record:' + prdList.size() + '\n';
                upsert prdList;
                // PricebookEntryにデータがない場合insertする、CNYとUSDのみ
                Pricebook2 pricebook = ControllerUtil.getStandardPricebook();

                String pricebookId = pricebook.Id;
                List<PricebookEntry> pbeList = [Select Product2Id, CurrencyIsoCode, UnitPrice, Pricebook2Id From PricebookEntry where Product2Id in: prdList and Pricebook2Id = :pricebookId order by Product2Id, CurrencyIsoCode];
                List<PricebookEntry> pbeInsertList = new List<PricebookEntry>();
                Map<String, PricebookEntry> rmbMap = new Map<String, PricebookEntry>();
                Map<String, PricebookEntry> usdMap = new Map<String, PricebookEntry>();
                for (PricebookEntry pbe : pbeList) {
                    if (pbe.CurrencyIsoCode == 'CNY') {
                        rmbMap.put(pbe.Product2Id, pbe);
                    } else if (pbe.CurrencyIsoCode == 'USD') {
                        usdMap.put(pbe.Product2Id, pbe);
                    }
                }
                for (Product2 prd : prdList) {
                    logstr += prd.ProductCode;
                    if (rmbMap.get(prd.Id) == null) {
                        PricebookEntry pbe = new PricebookEntry();
                        pbe.Pricebook2Id    = pricebookId;
                        pbe.Product2Id      = prd.Id;
                        pbe.CurrencyIsoCode = 'CNY';
                        pbe.UnitPrice       = 0;
                        pbe.IsActive        = prd.IsActive;
                        pbeInsertList.add(pbe);
                        logstr += ' add(CNY_0)';
                    }
                    if (usdMap.get(prd.Id) == null) {
                        PricebookEntry pbe = new PricebookEntry();
                        pbe.Pricebook2Id    = pricebookId;
                        pbe.Product2Id      = prd.Id;
                        pbe.CurrencyIsoCode = 'USD';
                        pbe.UnitPrice       = 0;
                        pbe.IsActive        = prd.IsActive;
                        pbeInsertList.add(pbe);
                        logstr += ' add(USD_0)';
                    }
                    logstr += ' ';
                }
                if (pbeInsertList.size() > 0) {
                    logstr += 'Execute Record2:' + pbeInsertList.size() + '\n';
                    insert pbeInsertList;
                }
            }
            logstr += '\nend';
            rowData.retry_cnt__c = 0;
        } catch (Exception ex) {
            // エラーが発生した場合
            Database.rollback(sp);
            System.debug(Logginglevel.ERROR, 'SBGITM_' + rowData.MessageGroupNumber__c + ':' + ex.getMessage());
            System.debug(Logginglevel.ERROR, 'SBGITM_' + rowData.MessageGroupNumber__c + ':' + ex.getStackTraceString());
            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 + '错误次数已经超过自动收信设定的最大次数，请手动收信';
            }
        }
        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) + ' ...';
        }
        update iflog;

    }
    /**
     * 为产品首营状态赋值
     * @param [prd] [产品]
     * @param [geData] [接口数据]
     * @return [产品]
     */
    public static Product2 product2NMPAStatus(Product2 prd, GeData geData) {

        //SSBG-CBPR
        Date dateFrom = '00000000'.equals(geData.StatusEffectiveDateFrom) ? Date.today() : NFMUtil.parseStr2Date(geData.StatusEffectiveDateFrom, false);
        Date oneStart = prd.MaterialStatus_one_Start__c;
        Date oneEnd = prd.MaterialStatus_one_End__c;
        Date twoStart = prd.MaterialStatus_two_Start__c;
        Date twoEnd = prd.MaterialStatus_two_End__c ;

        String campState = String.isBlank( geData.NMPAStatus) ? 'Z1' : geData.NMPAStatus;
        if (prd == null) {

            prd.NMPAStatus_one__c = campState;
            prd.MaterialStatus_one_Start__c = dateFrom;
            prd.MaterialStatus_one_End__c = NFMUtil.parseStr2Date('40001231', true);
        } else if ( oneStart == null || oneEnd < Date.today() || oneStart == dateFrom) {

            //if (twoEnd != null) {
            //    prd.MaterialStatus_two_End__c = dateFrom.addDays(-1);
            //}
            if (twoEnd != null && twoStart != dateFrom) {
                prd.MaterialStatus_two_End__c = dateFrom.addDays(-1);
            } else if (twoEnd != null && twoStart == dateFrom) {
                prd.MaterialStatus_two_Start__c = dateFrom.addDays(-1);
                prd.MaterialStatus_two_End__c = dateFrom.addDays(-1);

            }
            prd.NMPAStatus_one__c = campState;
            prd.MaterialStatus_one_Start__c = dateFrom;
            prd.MaterialStatus_one_End__c = NFMUtil.parseStr2Date('40001231', true);
        } else if (twoStart == null || twoEnd < Date.today() || twoStart == dateFrom) {

            prd.NMPAStatus_two__c = campState;
            prd.MaterialStatus_one_End__c = dateFrom.addDays(-1);
            prd.MaterialStatus_two_Start__c = dateFrom;
            prd.MaterialStatus_two_End__c = NFMUtil.parseStr2Date('40001231', true);
        } else {

            if ( (oneStart <= Date.today()) && (Date.today() <= oneEnd)) {
                prd.MaterialStatus_one_End__c = dateFrom.addDays(-1);
                prd.NMPAStatus_two__c = campState;
                prd.MaterialStatus_two_Start__c = dateFrom;
                prd.MaterialStatus_two_End__c = NFMUtil.parseStr2Date('40001231', true);
            } else if ( (twoStart <= Date.today()) && (Date.today() <= twoEnd)) {
                prd.MaterialStatus_two_End__c = dateFrom.addDays(-1);
                prd.NMPAStatus_one__c = campState;
                prd.MaterialStatus_one_Start__c = dateFrom;
                prd.MaterialStatus_one_End__c = NFMUtil.parseStr2Date('40001231', true);
            }
        }
        return prd;

    }

    public static String FieldTransformation(String bpCode, Map<String, String> transformation, String api, String toConvertStr, BatchIF_Log__c iflog, String receivesField ) {
        String afterTransformation = NFMUtil.getMapValue(transformation, api, toConvertStr, iflog);

        if (String.isNotBlank(afterTransformation) && !afterTransformation.equals(toConvertStr)) {

            return afterTransformation;
        } else {

            iflog.ErrorLog__c += 'BPCode[ ' + bpCode + ' ] of ' + receivesField + ' [ ' + toConvertStr + ' ]' + ' is  Invalid,This data is skipped.\n';
            return 'Invalid';
        }
    }
}