public with sharing class SSPowerBIBatch implements Database.Batchable<SObject> {
    public static Integer FIELDMAX = 200;
    private final List<Id> TEST_ID = null;
    private final Date createDate = null;
    private BatchIF_Log__c iflog;


    private static final Integer MAXERRORCNT = 20; // 邮件表单位最大错误信息显示数量
    private static final Boolean ALLORNONE = false; // 全部保存
    //--------------------------------------------------------------------------------------------------------------------------
    public SSPowerBIBatch() {
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = '备品备份：SSPowerBIBatch start\n';
        insert iflog;

    }
    public SSPowerBIBatch( Date createDate) {
        this.createDate = createDate;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = '备品备份：SSPowerBIBatch start\n';
        insert iflog;

    }
    public SSPowerBIBatch(List<Id> testId) {
        TEST_ID = testId;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = '备品备份：SSPowerBIBatch start\n';
        insert iflog;
    }

    public SSPowerBIBatch(List<Id> testId , Date createDate) {
        TEST_ID = testId;
        this.createDate = createDate;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = '备品备份：SSPowerBIBatch start\n';
        insert iflog;
    }
    //---------------------------------------------------------------------------------------------------------------------------
    public static String makeSql(SS_Batch_Column_Mapping__c setting, Set<String> apiTempSet) {
        //apiTempSet.add('Id');
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String fromColumn = 'From_Column_' + ('00' + i).right(3) + '__c';
            String apiStr = String.valueOf(setting.get(fromColumn));
            if (String.isBlank(apiStr) == false && apiTempSet.contains(apiStr) == false) {
                apiTempSet.add(apiStr);
            }
        }
        String soql = 'Select ' + String.join(new List<String>(apiTempSet), ',') + ' from ' + setting.Name;
        return soql;
    }
    //--------------------------------------------------------------------------------------------------------------------------
    public static Object getValue(SObject sobj, String field) {
        List<String> fieldPathList = field.split('\\.');
        Object rtn = null;
        for (Integer i = 0; i < fieldPathList.size(); i++) {
            String fieldPath = fieldPathList[i];
            if (i == fieldPathList.size() - 1) {
                rtn = sobj.get(fieldPath);
                if (rtn != null && String.valueOf(rtn).indexof('a href') >= 0 ) {
                    rtn = string.valueOf(rtn).replaceAll('<.*?>', '');
                }
            } else {
                sobj = sobj.getSObject(fieldPath);
                if (sobj == null) {
                    break;
                }
            }
        }
        return rtn;
    }
    //----------------------------------------------------------------------------------------------------------------------------
    public Database.QueryLocator start(Database.BatchableContext BC) {
        System.debug('-------------SSPower_BI_Batch start:');
        SS_Batch_Column_Mapping__c oppMapping = SS_Batch_Column_Mapping__c.getValues('Rental_Apply__c');
        Set<String> apiTempSet = new Set<String>();
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String lpadI = ('00' + i).right(3);
            String fromColumn = 'From_Column_' + lpadI + '__c';
            String apiStr = String.valueOf(oppMapping.get(fromColumn));
            if (String.isBlank(apiStr) == false) {
                String ssColumn = 'SS_Column_' + lpadI + '__c';
                String ssApiStr = String.valueOf(oppMapping.get(ssColumn));
                //apiTempSet.add(ssApiStr);
            }
        }
        String soql = makeSql(oppMapping, apiTempSet);

        if (TEST_ID <> null) {
            soql += ' where Id IN: TEST_ID';
        }else{
            // 2020/07/08 taoqz add start
            // 取消理由：主动取消剔除
            soql += ' where Cancel_Reason__c != \'主动取消\'';
        }
            // 2020/07/08 taoqz add end

        return Database.getQueryLocator(soql);
    }
    //--------------------------------------------------------------------------------------------------------------------------
    public void execute(Database.BatchableContext BC, List<Rental_Apply__c> oppList) {
        try {
            Date today = Date.today();
            if (today.day() == 1) {
                today = Date.newInstance(today.year(), today.month(), 1).addDays(-1);
            } else {
                today = Date.newInstance(today.addDays(1).year(),
                                         today.addDays(1).month(), 1).addDays(-1);
            }
            list<BatchIF_Log__c> ifloglist = [select id , ErrorLog__c from BatchIF_Log__c where id = :  iflog.id];
            if (ifloglist.size() > 0 ) {
                iflog = ifloglist[0];
            }
            List<SObject> insRACList = new List<SObject>();
            List<Id> insSSOppId = new List<Id>();
            // 商談
            SS_Batch_Column_Mapping__c oppMapping = SS_Batch_Column_Mapping__c.getValues('Rental_Apply__c');
            Schema.SObjectType ssOppType = Schema.getGlobalDescribe().get(String.valueOf(oppMapping.get('SS_TableName__c')));
            for (Rental_Apply__c opp : oppList) {
                Boolean updSelfFlg = false;
                SObject racObj = ssOppType.newSObject();
                for (Integer i = 1; i <= FIELDMAX; i++) {
                    String lpadI = ('00' + i).right(3);
                    String fromColumn = 'From_Column_' + lpadI + '__c';//From_Column_001__c
                    String apiStr = String.valueOf(oppMapping.get(fromColumn));
                    if (String.isBlank(apiStr) == false) {
                        String ssColumn = 'SS_Column_' + lpadI + '__c';
                        String ssApiStr = String.valueOf(oppMapping.get(ssColumn));
                        racObj.put(ssApiStr, getValue(opp, apiStr));
                    }
                }
                racObj.put('createDate__c', today);
                if (createDate != null) {
                    racObj.put('createDate__c', createDate);
                }
                insRACList.add(racObj);
                insSSOppId.add(opp.Id);
            }
            //--------------------------------------------------------------------------------------------------------------------
            List<SObject> raescList = new List<SObject>();
            List<Id> raescId = new List<Id>();
            SS_Batch_Column_Mapping__c oliMapping = SS_Batch_Column_Mapping__c.getValues('Rental_Apply_Equipment_Set__c');
            Set<String> apiTempSet = new Set<String>();
            String oliSql = makeSql(oliMapping, apiTempSet);
            oliSql += ' where Rental_Apply__c IN :insSSOppId';

            // 2020/07/08 taoqz add start
            // 取消理由：主动取消剔除
            if (TEST_ID == null) {
                oliSql += ' and Cancel_Reason__c != \'主动取消\'';
            }
            // 2020/07/08 taoqz add end

            Schema.SObjectType ssOliType = Schema.getGlobalDescribe().get(String.valueOf(oliMapping.get('SS_TableName__c')));
            for (Rental_Apply_Equipment_Set__c oli : Database.query(oliSql)) {
                SObject rscObj = ssOliType.newSObject();

                for (Integer i = 1; i <= FIELDMAX; i++) {
                    String lpadI = ('00' + i).right(3);
                    String fromColumn = 'From_Column_' + lpadI + '__c';
                    String apiStr = String.valueOf(oliMapping.get(fromColumn));
                    if (String.isBlank(apiStr) == false) {
                        String ssColumn = 'SS_Column_' + lpadI + '__c';
                        String ssApiStr = String.valueOf(oliMapping.get(ssColumn));
                        rscObj.put(ssApiStr, getValue(oli, apiStr));
                    }
                }
                rscObj.put('createDate__c', today);
                if (createDate != null) {
                    rscObj.put('createDate__c', createDate);
                }
                raescList.add(rscObj);
                raescId.add(oli.Id);
            }
            //---------------------------------------------------------------------------------------------------------------------
            List<SObject> raesdcList = new List<SObject>();
            List<Id> raesdcId = new List<Id>();
            SS_Batch_Column_Mapping__c rentalMapping = SS_Batch_Column_Mapping__c.getValues('Rental_Apply_Equipment_Set_Detail__c');
            Set<String> rentalTempSet = new Set<String>();
            String rentalSql = makeSql(rentalMapping, rentalTempSet);
            rentalSql += ' where Rental_Apply_Equipment_Set__c IN :raescId';

            // 2020/07/08 taoqz add start
            // 取消理由:重新分配，分配替代品，主动取消剔除
            // 备品用途附属品F=false  AND 是第一条备品配套明细=true
            // 回库确认完毕日：在2019年4月1日以前的剔除
            if (TEST_ID == null){
                Date arrivalwhday = Date.newInstance(2019, 4, 1);
                rentalSql += ' and Cancel_Reason__c != \'重新分配\' and Cancel_Reason__c != \'分配代替品\' and Cancel_Reason__c != \'主动取消\'';
                rentalSql += ' and Loaner_accsessary_F__c = false and Is_First_RAESD_F__c = true';
                rentalSql += ' and 	( Arrival_wh_day__c >= :arrivalwhday or Arrival_wh_day__c = null) ';
            }
            // 2020/07/08 taoqz add end

            Schema.SObjectType rentalType = Schema.getGlobalDescribe().get(String.valueOf(rentalMapping.get('SS_TableName__c')));
            for (Rental_Apply_Equipment_Set_Detail__c oli : Database.query(rentalSql)) {
                SObject reaObj = rentalType.newSObject();
                //raesdcList.add(reaObj);
                for (Integer i = 1; i <= FIELDMAX; i++) {
                    String lpadI = ('00' + i).right(3);
                    String fromColumn = 'From_Column_' + lpadI + '__c';
                    String apiStr = String.valueOf(rentalMapping.get(fromColumn));
                    if (String.isBlank(apiStr) == false) {
                        String ssColumn = 'SS_Column_' + lpadI + '__c';
                        String ssApiStr = String.valueOf(rentalMapping.get(ssColumn));
                        reaObj.put(ssApiStr, getValue(oli, apiStr));
                    }
                }
                reaObj.put('createDate__c', today);
                if (createDate != null) {
                    reaObj.put('createDate__c', createDate);
                }
                raesdcList.add(reaObj);
                raesdcId.add(oli.Id);
            }

            String tmp = iflog.ErrorLog__c;
            if (iflog.ErrorLog__c == null) {
                tmp = '';
            }

            list<id> ErrorIDlist = new list<id>();

            //insert insRACList;
            Database.SaveResult[] lsr2 = Database.insert(insRACList, false);
            for (SObject temRental_Apply : insRACList) {
                if (temRental_Apply.get('id') == null) {
                    ErrorIDlist.add( (ID) temRental_Apply.get('Id__c'));
                }
            }

            for (Integer tIdx = 0; tIdx < lsr2.size(); tIdx++) {
                Database.SaveResult sr = lsr2[tIdx];
                if (!sr.isSuccess()) {
                    String message = '';
                    for (Database.Error err : sr.getErrors()) {
                        message = '\n\n 错误数据类型:Rental_Apply__c'

                                  + '\n 错误信息：'
                                  + err.getStatusCode() + ':'
                                  + err.getMessage();
                        break;
                    }
                    tmp += message;
                }
            }

            //insert raescList;
            Database.SaveResult[] lsr3 = Database.insert(raescList, false);
            for (SObject temRaes : raescList) {
                if (temRaes.get('id') == null) {
                    ErrorIDlist.add( (ID) temRaes.get('Id__c'));
                }
            }

            for (Integer tIdx = 0; tIdx < lsr3.size(); tIdx++) {
                Database.SaveResult sr = lsr3[tIdx];
                if (!sr.isSuccess()) {
                    String message = '';
                    for (Database.Error err : sr.getErrors()) {
                        message = '\n\n 错误数据类型:Rental_Apply_Equipment_Set_Detail__c'
                                  + '\n 错误信息：'
                                  + err.getStatusCode() + ':'
                                  + err.getMessage();
                        break;
                    }
                    tmp += message;
                }
            }

            //insert raesdcList;
            Database.SaveResult[] lsr4 = Database.insert(raesdcList, false);
            for (SObject temraesdc : raesdcList) {
                if (temraesdc.get('id') == null) {
                    ErrorIDlist.add( (ID) temraesdc.get('Id__c'));
                }
            }
            for (Integer tIdx = 0; tIdx < lsr4.size(); tIdx++) {
                Database.SaveResult sr = lsr4[tIdx];
                if (!sr.isSuccess()) {
                    String message = '';
                    for (Database.Error err : sr.getErrors()) {
                        message = '\n\n错误数据类型:Rental_Apply_Equipment_Set__c'
                                  + '\n 错误信息：'
                                  + err.getStatusCode() + ':'
                                  + err.getMessage();
                        break;
                    }
                    tmp += message;
                }
            }
            if (ErrorIDlist.size() > 0 ) {
                tmp += '\n 更新失败原数据ID:' + ErrorIDlist;
            }
            if (tmp != null && tmp.length() > 65000) {
                tmp = tmp.substring(0, 65000);
                tmp += ' ...have more lines...';
            }
            iflog.ErrorLog__c = tmp;


        } catch (Exception ex) {
            iflog.ErrorLog__c += ex;

        }
        update iflog;

    }

    //--------------------------------------------------------------------------------------------------------------------------
    public void finish(Database.BatchableContext BC) {
        list<BatchIF_Log__c> ifloglist = [select id , ErrorLog__c, Log__c from BatchIF_Log__c where id = :  iflog.id];
        if (ifloglist.size() > 0 ) {
            iflog = ifloglist[0];
        }
        iflog.Log__c += '\n SSPowerBIBatch end';
        String tmp = iflog.ErrorLog__c;
        if (tmp != null && tmp.length() > 65000) {
            tmp = tmp.substring(0, 65000);
            tmp += ' ...have more lines...';
            iflog.ErrorLog__c = tmp;
        }
        upsert iflog;
    }


}