public without sharing class LoanerReminderSubmitLostBatchForTr  implements Database.Batchable<SObject>, Database.Stateful {
    public List<String> emailMessages = new List<String>();
    public Integer totalCount = 0; // 总件数
    public Integer failedCount = 0;
    public Date tdy = Date.today();
    public String query;

    public LoanerReminderSubmitLostBatchForTr() {
        this.query = query;
    }
    public 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('提交遗失报告书催促日期错误:两个月内没有指定的工作日');
        }
        String soql = 'SELECT Id,TransferApply__c,RecordType_F__c,TAESD_Status__c,Return_DeliverySlip__c, OneToOneAccessory__c,ArrivalResult__c,';
        soql += 'TransferApplySummary__r.Number_of_NG_received__c,TransferApplySummary__c, ';
        soql += 'Lost_item_giveup__c, Confirm_Lost_Date__c, Check_lost_Item_F__c,Main_OneToOne__c,';
        soql += ' Fixture_Model_No_F__c,Lost_item_check_day_F__c,Lost_item_Memo_F__c ';
        soql += ' FROM TransferApplyDetail__c WHERE Confirm_Lost_Date__c = null AND Lost_item_giveup__c = false ';
        soql += 'AND (Lost_item_check_day_F__c = :tdy OR Lost_item_check_day_F__c <= :reminderSubmitLostDate )';

        //和备品的不一样 调拨的判断条件区分了记录类型
        soql += ' and ( (Check_lost_Item_F__c = \'欠品\' AND (RecordType_F__c = \'CenterToCenter\' OR RecordType_F__c = \'AgencyToCenter\') ) ';
        //记录类型 = 备品中心到办事处 并且 调拨一览明细状态 != 丢失
        soql += ' OR ( RecordType_F__c = \'CenterToAgency\' AND TAESD_Status__c != \'丢失\' AND ';
        //回寄运输单 != 空 并且欠品确认结果 = 欠品
        soql += ' ((Return_DeliverySlip__c != null and Check_lost_Item_F__c = \'欠品\') OR ';
        //回寄运输单 = 空 并且 欠品确认结果 = 欠品 并且 (单一主体(主体 = true 并且 一对一主体 = false) = true 或者
        soql += ' (Return_DeliverySlip__c = null and Check_lost_Item_F__c = \'欠品\' AND ((Is_Body__c = true AND Main_OneToOne__c = false) ';
        //单独附属品(一对一附属品不勾 并且 备品用途附属品 = 打勾) = true
        soql += ' OR (OneToOneAccessory__c = false AND Loaner_accsessary__c = true)';
        //一对一附属品(附属品是勾并且一对一附属品也是勾) = true 并且 主体欠品确认结果(一对一保管主体sys = true 并且欠品确认结果=欠品)并且 (并且配套在其他一对一附属品调拨到货确认都 != NG 在下面的代码循环判断了)
        soql += ' OR (OneToOneAccessory__c = true AND Loaner_accsessary__c = true AND ArrivalResult__c != \'NG\') ) )) ) )';
        return Database.getQueryLocator(soql);
    }

    public void execute(Database.BatchableContext BC, list<TransferApplyDetail__c> trList) {
        System.debug('42222222222222222222222222222222222222');
        System.debug('43333333333333 trList '+trList);
        
        try{
            List<TransferApplyDetail__c> resultList = new List<TransferApplyDetail__c>();
            if (trList.size() > 0) {
                //一个调拨申请一览中 只要有一个状态是NG就不展示  一对一保管主体=true并且欠品确认结果=OK
                Map<Id,List<TransferApplyDetail__c>> map1 = new Map<Id,List<TransferApplyDetail__c>>();

                if (trList != null && trList.size() > 0) {
                  for (TransferApplyDetail__c detail : trList) {
                      //如果符合查询条件
                    if (detail.RecordType_F__c == 'CenterToAgency' && detail.TAESD_Status__c != '丢失' && detail.Return_DeliverySlip__c == null && detail.Check_lost_Item_F__c == '欠品'  && detail.OneToOneAccessory__c && detail.ArrivalResult__c != 'NG') {
                        //当调拨明细对应的调拨一览下的所有明细的调拨到货确认结果都不等于NG时,才可展示
                        if (Integer.valueOf(detail.TransferApplySummary__r.Number_of_NG_received__c) == 0) {
                            if (!map1.containsKey(detail.TransferApplySummary__c)) {
                                map1.put(detail.TransferApplySummary__c, new List<TransferApplyDetail__c>() );
                            }else{
                              List<TransferApplyDetail__c> tempList = map1.get(detail.TransferApplySummary__c);
                              tempList.add(detail);
                              map1.put(detail.TransferApplySummary__c, tempList );
                            }
                        }
                    }else {
                        //符合其他条件
                        System.debug('68:::::::::::::查到的明细::'+detail);
                        resultList.add(detail);
                    }
                  }
                }


                //再过滤一下 一对一附属品并且欠品对应的一览下的所有明细的 一对一保管主体(sys) 和欠品确认结果=OK
                if (map1.size() > 0) {
                  List<TransferApplyDetail__c> dlist = [SELECT Id,Name,TransferApply__c,RecordType_F__c,TAESD_Status__c,
                                                  TransferApplySummary__c,
                                                  Check_lost_Item_F__c,Main_OneToOne__c,Fixture_Model_No_F__c,
                                                  Lost_item_check_day_F__c,Lost_item_Memo_F__c         
                                                  FROM TransferApplyDetail__c WHERE TransferApplySummary__c in :map1.keySet()];
                  if (dlist !=null && dlist.size() > 0) {
                      for (TransferApplyDetail__c detail : dlist) {
                        //如果 (一对一保管主体(sys) =true 和欠品确认结果 = OK) 是false 那么这个一览下的所有明细都不展示 反之 展示
                          // if (!(detail.Main_OneToOne__c && detail.Check_lost_Item_F__c == 'OK')) {
                          if ((detail.Main_OneToOne__c  && detail.Check_lost_Item_F__c != 'OK') || (!detail.Main_OneToOne__c  && detail.Check_lost_Item_F__c == 'OK')){
                            if (map1.containsKey(detail.TransferApplySummary__c)) {
                                map1.remove(detail.TransferApplySummary__c); 
                            }
                          }
                      }
                  }
                  for (TransferApplyDetail__c detail : dlist) {
                    if (map1.containsKey(detail.TransferApplySummary__c) && detail.Check_lost_Item_F__c == '欠品') {
                        resultList.add(detail);
                    }
                  }

                  Set<TransferApplyDetail__c> tempSet = new Set<TransferApplyDetail__c>();
                  tempSet.addAll(resultList);
                  resultList = new List<TransferApplyDetail__c>();
                  resultList.addAll(tempSet);
                }
            }
            if (resultList.size() > 0) {
                System.debug('109999:::resultList '+resultList);
                String raId = '';
                String reminderMessage = '';
                String noticeMessage = '';
                List<TransferApply__c> ra1List = new List<TransferApply__c>();
                List<TransferApply__c> ra2List = new List<TransferApply__c>();
                for (TransferApplyDetail__c raesd : resultList) {
                    if (String.isBlank(raId) || raId != raesd.TransferApply__c) {
                        if (String.isNotBlank(raId)) {
                            TransferApply__c ra1 = new TransferApply__c(Id = raId);
                            TransferApply__c ra2 = new TransferApply__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.TransferApply__c;
                        reminderMessage = '';
                        noticeMessage = '';
                    }
                    if (raesd.Lost_item_check_day_F__c == tdy) {
                        noticeMessage += raesd.Fixture_Model_No_F__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_F__c + ' <BR>';
                    }
                }
                if (String.isNotBlank(raId)) {
                    TransferApply__c ra1 = new TransferApply__c(Id = raId);
                    TransferApply__c ra2 = new TransferApply__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());
        }
    }

    public 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;
    }
}