global without sharing class ConsumApplyInventoryAutoDeleteBatch implements Database.Batchable<sObject>, Database.Stateful {

    global List<String> emailMessages = new List<String>();
    global Integer totalCount = 0; // 総処理件数
    global Integer totalCountDone = 0; // 処理済件数
    global Integer failedCount = 0; // 処理失敗件数
    global Integer dateLimit = 0; // (dateLimit)日以上申請を出さないと、明細をクリア

    Boolean IsNeedExecute = false; // 2021-03-05  mzy  WLIG-BYHD79  SFDC环境batch合并调查  是否符合执行条件

    global ConsumApplyInventoryAutoDeleteBatch(Integer dateLimit) {
        this.dateLimit = dateLimit;
    }

    //2021-06-07 mzy  WLIG-BYHD79  SFDC环境batch合并调查 start
    global ConsumApplyInventoryAutoDeleteBatch(Integer dateLimit,Boolean needExecute) {
        this.dateLimit = dateLimit;

        this.IsNeedExecute = needExecute;  // 2021-03-05  mzy  WLIG-BYHD79  SFDC环境batch合并调查  
    }
    //2021-06-07 mzy  WLIG-BYHD79  SFDC环境batch合并调查 end

    /**
     * startには、queryを実行、耗材备品申請を検索
     */
    global Database.Querylocator start(Database.BatchableContext bc) {
        String query = 'select Id from Consum_Apply__c';
        query += ' where (Status__c = \'草案中\' or Status__c = \'填写完毕\' or Status__c = \'不批准\' or Status__c = \'取消\' or Status__c = \'删除\')';
        query += ' and Consum_Apply_Equipment_Set_Detail_Cnt__c > 0';
        query += ' order by Id';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext bc, List<Consum_Apply__c> csmApyList) {
        totalCount += csmApyList.size();
        Savepoint sp = Database.setSavepoint();
        try {
            List<Consum_Apply_Equipment_Set_Detail__c> toDeleteDtlList = getDeleteDetialList(csmApyList, dateLimit);

            // 明細を削除
            List<Database.DeleteResult> delResult = Database.delete(toDeleteDtlList, false);
            if (this.emailMessages.size() < 100) {
                this.emailMessages = FixtureUtil.setDelError(delResult, Consum_Apply_Equipment_Set_Detail__c.sObjectType, toDeleteDtlList, this.emailMessages);
            }
            totalCountDone += csmApyList.size();
        }
        catch (Exception e) {
            emailMessages.add(e.getMessage());
            failedCount += csmApyList.size();
            Database.rollback(sp);
        }
    }

    global void finish(Database.BatchableContext bc) {
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{UserInfo.getUserEmail()};
        String emailLabel = 'BatchNotify';
        for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName 
                FROM OrgWideEmailAddress
                WHERE DisplayName like :emailLabel]) {
            toList = new String[]{tmpEmailObj.Address};
        }
        String title = '自动释放库存';
        List<String> ccList = new List<String>();
        for (Consum_Apply_Meta__mdt camd : [SELECT Id
                    , Key__c
                    , ValueLong__c
                 FROM Consum_Apply_Meta__mdt
                WHERE Package__c = 'ConsumApplyInventoryAutoDeleteBatch'
                  AND (Key__c = 'ErrorMailAddress'
                          OR Key__c = 'ErrorMailTitle'
                      )
                ORDER BY Key__c]) {
            if (camd.Key__c == 'ErrorMailAddress') {
                if (String.isNotBlank(camd.ValueLong__c)) {
                    ccList.addAll(camd.ValueLong__c.split(','));
                }
            }
            else if (camd.Key__c == 'ErrorMailTitle') {
                title = camd.ValueLong__c;
            }
        }
        if (!(totalCountDone == totalCount && 0 == emailMessages.size())) {
            be.failedMail(toList, ccList, title,
                String.join(this.emailMessages, '\n'),
                totalCount, totalCountDone, failedCount);
            be.send();
        }


    }

    public static List<Consum_Apply_Equipment_Set_Detail__c> getDeleteDetialList(List<Consum_Apply__c> pCsmApyList, Integer pDateLimit) {
        // 明細リスト
        List<Consum_Apply_Equipment_Set_Detail__c> csmApyDtlList =
            [SELECT Id,
                    Name,
                    Consum_Apply__c
               FROM Consum_Apply_Equipment_Set_Detail__c
              WHERE Consum_Apply__c in : pCsmApyList
           ORDER BY Id];

        // 明細MAP＜申請ID,明細リスト＞
        Map<Id, List<Consum_Apply_Equipment_Set_Detail__c>> csmApyDtlMap = new Map<Id, List<Consum_Apply_Equipment_Set_Detail__c>>();
        for (Consum_Apply_Equipment_Set_Detail__c csmApyDtlObj : csmApyDtlList) {
            if (csmApyDtlMap.get(csmApyDtlObj.Consum_Apply__c) == null) {
                csmApyDtlMap.put(csmApyDtlObj.Consum_Apply__c, new List<Consum_Apply_Equipment_Set_Detail__c>());
            }
            List<Consum_Apply_Equipment_Set_Detail__c> eachDtlList = csmApyDtlMap.get(csmApyDtlObj.Consum_Apply__c);
            eachDtlList.add(csmApyDtlObj);
        }

        // 作成日最小値の集計
        List<AggregateResult> groupedResults =
            [SELECT Consum_Apply__c,
                    MIN(CreatedDate) min
               FROM Consum_Apply_Equipment_Set_Detail__c
              WHERE Consum_Apply__c in : pCsmApyList
           GROUP BY Consum_Apply__c];
        Date minDate = Date.today();
        Date maxDate = Date.today();
        for (AggregateResult ar : groupedResults) {
            // 作成日最小値
            Datetime createDT = (Datetime) ar.get('min');
            Date caesdCreateDate = createDT.date();
            if (minDate > caesdCreateDate) {
                minDate = caesdCreateDate;
            }
            if (maxDate < caesdCreateDate) {
                maxDate = caesdCreateDate;
            }
        }
        Map<Date, OlympusCalendar__c> calMap = Consum_ApplyUtil.getOlympusCalendarMAp(minDate, maxDate);

        // 削除待ち明細リスト
        List<Consum_Apply_Equipment_Set_Detail__c> toDeleteDtlList = new List<Consum_Apply_Equipment_Set_Detail__c>();
        for (AggregateResult ar : groupedResults) {
            // 作成日最小値
            Datetime createDT = (Datetime) ar.get('min');
            Date caesdCreateDate = createDT.date();
            Date deleteTargetDay;
            if (pDateLimit > 0) {
                if (calMap.get(caesdCreateDate).get('After_' + pDateLimit + '_WorkDay__c') != null) {
                    deleteTargetDay = Date.valueOf(calMap.get(caesdCreateDate).get('After_' + pDateLimit + '_WorkDay__c'));
                }
            }
            if (null == deleteTargetDay) {
                deleteTargetDay = Consum_ApplyUtil.getWD_addday(caesdCreateDate, pDateLimit);
            }

            // 申請を2日以上出さない場合、明細を削除待ちリストに追加
            if (Date.today() >= deleteTargetDay) {
                toDeleteDtlList.addAll(csmApyDtlMap.get(String.valueOf(ar.get('Consum_Apply__c'))));
            }
        }

        return toDeleteDtlList;
    }
}