global class LoanerReminderSubmitLostBatch implements Database.Batchable<sObject>, Database.Stateful {
    global List<String> emailMessages = new List<String>();
    global Integer totalCount = 0; // 总件数
    global Integer failedCount = 0;
    global Date tdy = Date.today();

    /**
     * startには、queryを実行、备品Set明细を検索
    */
    global Database.QueryLocator start(Database.BatchableContext BC) {
        bp3_Setting__c conf = bp3_Setting__c.getOrgDefaults();
        Date reminderSubmitLostDate = getSSday(tdy, -(conf.Reminder_Submit_Lost__c == null ? 13 : Integer.valueOf(conf.Reminder_Submit_Lost__c)), 2);
        if (reminderSubmitLostDate == null) {
            reminderSubmitLostDate = Date.newInstance(1970, 1, 1);
            emailMessages.add('提交遗失报告书催促日期错误:两个月内没有指定的工作日');
        }
        Set<String> raIdSet = new Set<String>();
        for (Rental_Apply_Equipment_Set_Detail__c raesd : [SELECT Rental_Apply__c
                 FROM Rental_Apply_Equipment_Set_Detail__c
                WHERE Confirm_Lost_Date__c = null
                  AND Lost_item_giveup__c = false
                  AND Check_lost_Item_F__c = '欠品'
                  AND Return_DeliverySlip__c = null
                  AND (Lost_item_check_day_F__c = :tdy
                          OR Lost_item_check_day_F__c <= :reminderSubmitLostDate
                      )
                ]) {
            raIdSet.add(raesd.Rental_Apply__c);
        }
        return Database.getQueryLocator([SELECT Id
                 FROM Rental_Apply__c
                WHERE Id = :raIdSet
                ORDER BY Id]
        );
    }

    global void execute(Database.BatchableContext BC, List<Rental_Apply__c> saList) {
        totalCount = saList.size();
        bp3_Setting__c conf = bp3_Setting__c.getOrgDefaults();
        Date reminderSubmitLostDate = getSSday(tdy, -(conf.Reminder_Submit_Lost__c == null ? 13 : Integer.valueOf(conf.Reminder_Submit_Lost__c)), 2);
        try{
            List<Rental_Apply_Equipment_Set_Detail__c> raesdList = [SELECT Id
                        , Rental_Apply__c
                        , Fixture_Model_No_text__c
                        , Lost_item_check_day_F__c
                        , Lost_item_Memo_F__c
                     FROM Rental_Apply_Equipment_Set_Detail__c
                    WHERE Rental_Apply__c = :saList
                      AND Confirm_Lost_Date__c = null
                      AND Lost_item_giveup__c = false
                      AND Check_lost_Item_F__c = '欠品'
                      AND Return_DeliverySlip__c = null
                      AND (Lost_item_check_day_F__c = :tdy
                              OR Lost_item_check_day_F__c <= :reminderSubmitLostDate
                          )
                    ORDER BY Rental_Apply__c, Lost_item_check_day_F__c];
            if (raesdList.size() > 0) {
                String raId = '';
                String reminderMessage = '';
                String noticeMessage = '';
                List<Rental_Apply__c> ra1List = new List<Rental_Apply__c>();
                List<Rental_Apply__c> ra2List = new List<Rental_Apply__c>();
                for (Rental_Apply_Equipment_Set_Detail__c raesd : raesdList) {
                    if (String.isBlank(raId) || raId != raesd.Rental_Apply__c) {
                        if (String.isNotBlank(raId)) {
                            Rental_Apply__c ra1 = new Rental_Apply__c(Id = raId);
                            Rental_Apply__c ra2 = new Rental_Apply__c(Id = raId);
                            if (String.isNotBlank(reminderMessage)) {
                                ra1.Reminder_Submit_LostText__c = null;
                                ra2.Reminder_Submit_LostText__c = reminderMessage;
                            }
                            if (String.isNotBlank(noticeMessage)) {
                                ra1.Lost_Item_Email_Detail__c = null;
                                ra2.Lost_Item_Email_Detail__c = noticeMessage;
                            }
                            ra1List.add(ra1);
                            ra2List.add(ra2);
                        }
                        raId = raesd.Rental_Apply__c;
                        reminderMessage = '';
                        noticeMessage = '';
                    }
                    if (raesd.Lost_item_check_day_F__c == tdy) {
                        noticeMessage += raesd.Fixture_Model_No_text__c;
                        String memo = String.isBlank(raesd.Lost_item_Memo_F__c) ? '' : raesd.Lost_item_Memo_F__c;
                        noticeMessage += '&nbsp;欠品备注:' + memo + '<BR>';
                    }
                    else {
                        reminderMessage += raesd.Fixture_Model_No_text__c + '<BR>';
                    }
                }
                if (String.isNotBlank(raId)) {
                    Rental_Apply__c ra1 = new Rental_Apply__c(Id = raId);
                    Rental_Apply__c ra2 = new Rental_Apply__c(Id = raId);
                    if (String.isNotBlank(reminderMessage)) {
                        ra1.Reminder_Submit_LostText__c = null;
                        ra2.Reminder_Submit_LostText__c = reminderMessage;
                    }
                    if (String.isNotBlank(noticeMessage)) {
                        ra1.Lost_Item_Email_Detail__c = null;
                        ra2.Lost_Item_Email_Detail__c = noticeMessage;
                    }
                    ra1List.add(ra1);
                    ra2List.add(ra2);
                }
                if (ra1List.size() > 0) {
                    FixtureUtil.withoutUpdate(ra1List);
                    FixtureUtil.withoutUpdate(ra2List);
                }
            }
        }
        catch(Exception e) {
            emailMessages.add(e.getMessage());
            failedCount += saList.size();
        }
    }

    global void finish(Database.BatchableContext BC) {
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{UserInfo.getUserEmail()};
        String title = '欠品确认通知, 提交遗失报告书催促 的邮件Batch处理';
        String[] ccList = null;
        if(this.emailMessages.size() == 0){
            // be.successMail(toList, ccList, title, totalCount);
        }else{
            be.failedMail(toList, ccList, title,
                    String.join(this.emailMessages, '\n'),
                    totalCount, totalCount - failedCount, failedCount);
            be.send();
        }
    }

    public static Date getSSday(Date da, Integer execute_Day, Integer maxMonth) {
        Date maxDate = da.addMonths(execute_Day > 0 ? maxMonth : -maxMonth);
        Integer execute_Dayabs = Math.abs(execute_Day);
        String soql = 'Select Date__c '
              + ' From OlympusCalendar__c'
             + ' WHERE Date__c ' + (execute_Day >0 ? '>=' : '<=') + ' :da'
              + '  AND IsWorkDay__c = 1'
              + '  AND Date__c ' + (execute_Day <0 ? '>=' : '<=') + ' :maxDate'
              + ' order by Date__c ' + (execute_Day > 0 ? 'asc' : 'DESC') + ' limit ' + execute_Dayabs;
        List<OlympusCalendar__c> ssDay = Database.query(soql);
        Date da1;
        if (ssDay.size() >= execute_Dayabs) {
            da1 = ssDay[execute_Dayabs -1].Date__c;
        }
        return da1;
    }
}