global class OPDPlanMarkBatch implements Database.Batchable<sObject>, Database.Stateful {
    //SWAG-BA65JL 2019/03/22   XHL AddStart
    public static Integer FIELDMAX = 200;
    //String query;
    List<String> oPDPlanIds = null;
    private BatchIF_Log__c iflog;
    //private String thismonth_Lastday;

    global OPDPlanMarkBatch() {
        // CHAN-BBW5DQ 20190507 LHJ Start
        //thismonth_Lastday = String.valueOf(Date.toDay().addMonths(1).toStartOfMonth().addDays(-1));
        //thismonth_lastday = String.valueOf(Date.toDay().addMonths(-1).toStartOfMonth());
        // CHAN-BBW5DQ LHJ 20190507  End
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = 'OPDPlanMarkBatch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    /**
    //  格式 为"2019-03-31"
    global OPDPlanMarkBatch(string thismonth_Lastday) {
        this.thismonth_Lastday = thismonth_Lastday;
    }
    **/
    // 指定"OPD计划"的Id
    global OPDPlanMarkBatch(List<String> oPDPlanIds) {
        this.oPDPlanIds = oPDPlanIds;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'PushNotification';
        iflog.Log__c  = 'OPDPlanMarkBatch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }


    global Database.QueryLocator start(Database.BatchableContext BC) {
        // select項目を opdpMapping より生成
        SS_Batch_Column_Mapping__c opdpMapping = SS_Batch_Column_Mapping__c.getValues('OPDPlan__c');
        Set<String> apiTempSet = new Set<String>();
        //apiTempSet.add('StageName');
        for (Integer i = 1; i <= FIELDMAX; i++) {
            String lpadI = ('00' + i).right(3);
            String fromColumn = 'From_Column_' + lpadI + '__c';
            String apiStr = String.valueOf(opdpMapping.get(fromColumn));
            if (String.isBlank(apiStr) == false) {
                String ssColumn = 'SS_Column_' + lpadI + '__c';
                String ssApiStr = String.valueOf(opdpMapping.get(ssColumn));
                if (ssApiStr.toLowerCase().startsWith('opdplan__c.')) {
                    // 商談の項目を更新、変更があるかどうか判断するため、元データも取得
                    //System.debug('ssApiStr=' + ssApiStr + ', substring(11)=' + ssApiStr.substring(11));
                    apiTempSet.add(ssApiStr.substring(11));
                }
            }
        }
        Date dateNow = Date.today();
        Integer year = dateNow.year();
        Integer month = dateNow.month();
        if (month < 4) {
            year -= 1;
        }
        Integer nextYear = year+1;
        Date thisYd = Date.valueOf(year+'-4-1');
        Date nextYd = Date.valueOf(nextYear+'-4-1');
        Date thisMonth = Date.newInstance(Date.today().year(),Date.today().month(),1);
        Date nextMonth = Date.newInstance(Date.today().year(), Date.today().month(), 1).addMonths(1);

        String soql = makeSql(opdpMapping, apiTempSet);
        if (oPDPlanIds <> null) {
            soql += ' where Id IN: oPDPlanIds';
            soql += ' and ((CompleteDate__c != Null and CompleteDate__c >=  :thisYd and CompleteDate__c <=  :nextYd) OR CompleteDate__c = Null ) and';
            soql += ' ((CancelDate__c != Null and  CancelDate__c >= :thisMonth and  CancelDate__c < :nextMonth)';
            soql += ' or (CompleteDate__c != Null and  CompleteDate__c >= :thisMonth and CompleteDate__c < :nextMonth)';
            soql += ' or Status__c=\'草案中\' or Status__c=\'审批中\' or Status__c=\'计划中\' or Status__c=\'完毕未报告\' or Status__c=\'待提交报告\')';

        } else {
           /**
           //DB202305276593 you 20230526 注释，因为工作流一直没启用，导致最终处理日 一直是空，所以拍照也一直是全量拍 ,增加下面逻辑
            Date nowDay = Date.valueOf(thismonth_Lastday);
            // CHAN-BBW5DQ 20190507 LHJ Start
            //soql += ' Where OPDPlan_ImplementDate__c <=  : nowDay';
            soql += ' Where FinalDate__c = Null or FinalDate__c >=  :nowDay';
            // CHAN-BBW5DQ 20190507 LHJ End
            System.debug('nowDay=' + nowDay);
            **/
            /**
                ​大前提：对于完毕日不空，只拍完毕日在本财年的，或者完毕日空的：
                再判断：
                1. 取消，完毕的再看日期是不是在当月，在当月需要拍照；
                2. 剩下的状态：草案中、审批中、计划中、完毕未报告、待提交报告，全部拍照
            **/
            soql += ' Where ((CompleteDate__c != Null and CompleteDate__c >=  :thisYd and CompleteDate__c <=  :nextYd) OR CompleteDate__c = Null ) and';
            soql += ' ((CancelDate__c != Null and  CancelDate__c >= :thisMonth and  CancelDate__c < :nextMonth)';
            soql += ' or (CompleteDate__c != Null and  CompleteDate__c >= :thisMonth and CompleteDate__c < :nextMonth)';
            soql += ' or Status__c=\'草案中\' or Status__c=\'审批中\' or Status__c=\'计划中\' or Status__c=\'完毕未报告\' or Status__c=\'待提交报告\')';

        }
        System.debug('thisMonth=='+thisMonth+'==nextMonth=='+nextMonth);
        System.debug('thisYd=='+thisYd+'==nextYd=='+nextYd+'soql=' + soql);
        return Database.getQueryLocator(soql);

    }

    global void execute(Database.BatchableContext BC, List<OPDPlan__c> OPDPlans) {
        List<OPDPlan__c> updSelfList = new List<OPDPlan__c>();
        List<SObject> insSSOpdpList = new List<SObject>();
        // 商談
        SS_Batch_Column_Mapping__c opdpMapping = SS_Batch_Column_Mapping__c.getValues('OPDPlan__c');
        Schema.SObjectType ssOppType = Schema.getGlobalDescribe().get(String.valueOf(opdpMapping.get('SS_TableName__c')));
        for (OPDPlan__c opdp : OPDPlans) {
            Boolean updSelfFlg = false;
            SObject insSSOpdp = ssOppType.newSObject();
            for (Integer i = 1; i <= FIELDMAX; i++) {
                String lpadI = ('00' + i).right(3);
                String fromColumn = 'From_Column_' + lpadI + '__c';
                String apiStr = String.valueOf(opdpMapping.get(fromColumn));
                if (String.isBlank(apiStr) == false) {
                    String ssColumn = 'SS_Column_' + lpadI + '__c';
                    String ssApiStr = String.valueOf(opdpMapping.get(ssColumn));
                    if (ssApiStr.toLowerCase().startsWith('opdplan__c.')) {
                        // 項目更新、変更判断
                        if (opdp.get(ssApiStr.substring(11)) != opdp.get(apiStr)) {
                            try {
                                opdp.put(ssApiStr.substring(11), opdp.get(apiStr));
                                updSelfFlg = true;
                            } catch (Exception e) {
                                iflog.ErrorLog__c = 'ERROR [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                            }
                        }
                    } else {
                        try {
                            insSSOpdp.put(ssApiStr, getValue(opdp, apiStr));
                        } catch (Exception e) {
                            iflog.ErrorLog__c = 'ERROR ' + String.valueOf(opdpMapping.get('SS_TableName__c')) + ' [' + apiStr + '] => [' + ssApiStr + ']' + e.getMessage() + '\n';
                        }
                    }
                }
            }
            if (updSelfFlg) {
                updSelfList.add(opdp);
            }
            insSSOpdpList.add(insSSOpdp);
        }

        // 记下更新OPD计划错误log
        if (updSelfList.size() > 0) {
            Database.SaveResult[] lsr = Database.update(updSelfList, false);
            for (Integer tIdx = 0; tIdx < lsr.size(); tIdx++) {
                Database.SaveResult sr = lsr[tIdx];
                if (!sr.isSuccess()) {
                    Database.Error emsg = sr.getErrors()[0];
                    if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {

                        iflog.ErrorLog__c += 'ERROR ' + updSelfList[tIdx].Id + ' OPDPlan__c:' + emsg + '\n';
                    }
                }
            }
        }

        //插入备份表
        Database.SaveResult[] lsr2 = Database.insert(insSSOpdpList, false);
        for (Integer tIdx = 0; tIdx < lsr2.size(); tIdx++) {
            Database.SaveResult sr = lsr2[tIdx];
            if (!sr.isSuccess()) {
                Database.Error emsg = sr.getErrors()[0];
                // 2020-11-27  mzy  update    原:insSSOpdpList[tIdx].get('OPDPlan__c')  改为  insSSOpdpList[tIdx].get('SSOPDPlan__c')
                if (!String.valueOf(emsg.getStatusCode()).contains('INACTIVE_OWNER_OR_USER')) {
                    iflog.ErrorLog__c += 'ERROR ' + insSSOpdpList[tIdx].get('SSOPDPlan__c') + ' SS_opd:' + emsg + '\n';
                }
            }
        }



    }

    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);
            } else {
                sobj = sobj.getSObject(fieldPath);
                if (sobj == null) {
                    break;
                }
            }
        }
        return rtn;
    }
    global void finish(Database.BatchableContext BC) {
        iflog.Log__c += '\nOPDPlanMarkBatch end';
        String tmp = iflog.ErrorLog__c;
        if (tmp.length() > 65000) {
            tmp = tmp.substring(0, 65000);
            tmp += ' ...have more lines...';
            iflog.ErrorLog__c = tmp;
        }
        update iflog;
        //------20200330-----XHL-----AddStart
        //以下为每个季度的第一个工作日执行，分别为4月、7月、10月、1月的第一个工作日执行，
        //OPD计划的特别执行，季度计划不参与执行，若需要执行，请调OPDQuarterPlanPhotographBatch里面的方法去执行，特此说明
        //  Date toDate = Date.today();
        //  Date yesterDate = toDate.addDays(-1);
        //   Integer executeMonth = toDate.month();
        //  Date mon1stDate = Date.newInstance(toDate.year(), toDate.month(), 1);
        //  //每月到今天的工作日
        //  Integer workdays = UpdateUserTextColBatch.getOlympusWorkDayCount(mon1stDate, toDate);
        //  //每月到昨天的工作日
        //  Integer workdays1 = UpdateUserTextColBatch.getOlympusWorkDayCount(mon1stDate, yesterDate);

        // Integer OSFBacth_Execute_Day = Integer.valueOf(System.Label.OSFBacth_Execute_Day);
        //  if (workdays1 != OSFBacth_Execute_Day && workdays == OSFBacth_Execute_Day) {
        //      if ( executeMonth == 1 || executeMonth == 4 || executeMonth == 7 || executeMonth == 10) {
        //          if (oPDPlanIds <> null ) {
        //              //Database.executebatch(new OPDQuarterPlanPhotographBatch(oPDPlanIds), 100);
        //          } else{
        //              Database.executebatch(new OPDQuarterPlanPhotographBatch(), 100);
        //          }

        //      }

        //  }     修改在schedule里调用。符合倒数第二天，就调月度。符合季度，就调季度 (移至 OPDPlanMarkBatchSchedule)

        // 2020-11-25   mzy  add  ss拷贝之后,发送邮件  start
        boolean result =  sendMail();
        if (!result) {
            System.debug('邮件发送失败,请检查');
        }
        // 2020-11-25   mzy  add  ss拷贝之后,发送邮件  end

    }

    public static boolean sendMail() {

        Boolean result = true;
        String title = '';
        String body = '';
        List<String> toMailList = new List<String>();
        //List<String> ccMailList = new List<String>();
        List<String> statementIdList = new List<String>();
        Date today = Date.today();

        // 标题与内容
        title = 'OPD计划排序拍照已经完成';
        body += '各位好！<br/>';
        body += '<br/>本月的OPD计划排序结果拍照已经完成，请参考以下报表查看详细信息：<br/>';
        body += '<a href="' + URL.getSalesforceBaseUrl().toExternalForm() + '/' + System.Label.SSOPD_Report + '">'
                + URL.getSalesforceBaseUrl().toExternalForm() + '/' + System.Label.SSOPD_Report + '</a><br/>';

        body += '<br/>谢谢';

        //收件人与抄送人
        //1. 邮件群组
        String str = System.Label.OPDTPMailboxGroup;
        toMailList.addAll(str.split(';'));
        //2. 公共小组
        //用来存放用户的id
        List<String> idList = new List<String>();
        //查询公用小组
        List<Group> gList = [ SELECT (select userOrGroupId from groupMembers) FROM group WHERE name = 'OPD拍照收件人'];
        if (gList != null && gList.size() > 0) {
            for (Group g : gList) {
                for (GroupMember gm : g.groupMembers) {
                    idList.add(gm.userOrGroupId);
                }
            }
        }

        //根据用户id查询用户信息
        List<User> usrList = [SELECT email FROM user WHERE id in :idList];
        //获取各个用户的email
        for (User u : usrList) {
            toMailList.add(u.email);
        }


        List<Messaging.SingleEmailMessage> sendMails = new List<Messaging.SingleEmailMessage>();
        Messaging.SingleEmailMessage messageNEW = new Messaging.SingleEmailMessage();
        messageNEW.setSubject(title);
        messageNEW.setHtmlBody(body);
        messageNEW.setCharset('UTF-8');
        messageNEW.setToAddresses(toMailList);
        //messageNEW.setCcAddresses(ccMailList);

        sendMails.add(messageNEW);
        if (sendMails.size() > 0) {
            Messaging.SendEmailResult[] results = messaging.sendEmail(sendMails);
            for (Integer i = 0; i < results.size(); i++) {
                if (results[i].success == false) {
                    system.debug('=====send mail error:' + results[i].errors[0].message);
                    result = false;
                }
            }
        }
        return result;
    }
    

}