global class SetCurrentDailyReportSumBatch implements Database.Batchable < sObject > , Database.Stateful {
    String query;
    String yearField;
    //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql  2020/05/29 start
    String yearWorkDay;
    String lastYearWorkDay;
    //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql 2020/05/29 end
    Date toDate;
    Id userId;
    //用于传入的财年
    Integer flag;
    //该财年的开始日
    Date fromDate1 = null;
    //该财年的结束日
    Date endDate = null;
    //上财年的开始日
    Date fromDate2 = null;
    //上财年的结束日
    Date endDate1 = null;

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

    global SetCurrentDailyReportSumBatch() {
        toDate = Date.today();
    }
    global SetCurrentDailyReportSumBatch(Date d, Id id) {
        toDate = d;
        userId = id;
    }
    //根据财年更新所有用户
    global SetCurrentDailyReportSumBatch(Integer year) {
        flag = year;
        toDate = Date.today();
    }
    //根据财年和userid 更新单个的用户
    global SetCurrentDailyReportSumBatch(Integer year, Id id) {
        flag = year;
        userId = id;
        toDate = Date.today();
    }
    //更新本财年所有用户
    global SetCurrentDailyReportSumBatch(Id id) {
        userId = id;
        toDate = Date.today();
    }
    // 2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  start
    global SetCurrentDailyReportSumBatch(Boolean NeedExecute) {
        this.IsNeedExecute = NeedExecute;
        this.toDate = Date.today();
    }
    // 2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  end

    global Database.QueryLocator start(Database.BatchableContext BC) {
        if (toDate.month() == 4 && toDate.day() == 1) {
            yearField = 'Daily_Report_Num_';
            yearField += String.valueOf(toDate.year() - 1 - 1867) + 'P__c';
        }
        
        //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql  2020/05/29 start
        if (flag != null) {
            //根据传入的财年 去判断该财年的开始日期
            fromDate1 = Date.newInstance(flag + 1867, 4, 1);
            endDate = Date.newInstance(flag + 1 + 1867, 4, 1);
            //根据传入的财年 去判断上财年的开始日期
            fromDate2 =Date.newInstance(flag + 1867 - 1, 4, 1);
            endDate1 =Date.newInstance(flag  + 1867, 4, 1);

            //该财年要更新的字段
            yearWorkDay = 'WorkDate';
            yearWorkDay += String.valueOf(flag) + 'P__c';
            //上次啊年要更新的字段
            lastYearWorkDay = 'WorkDate';
            lastYearWorkDay += String.valueOf(flag -1) + 'P__c';

        } else {
            //根据当前时间判断本财年
            if (toDate.month() >= 4) {
                fromDate1 = Date.newInstance(toDate.year(), 4, 1);
                endDate = Date.newInstance(toDate.year() + 1, 4, 1);
                fromDate2 = Date.newInstance(toDate.year() - 1, 4, 1);
                endDate1 = Date.newInstance(toDate.year(), 4, 1);
            } else {
                fromDate1 = Date.newInstance(toDate.year() - 1, 4, 1);
                endDate = Date.newInstance(toDate.year(), 4, 1);
                fromDate2 = Date.newInstance(toDate.year() - 2, 4, 1);
                endDate1 = Date.newInstance(toDate.year()- 1, 4, 1);
            }
            if (fromDate1 == toDate) {
                fromDate1 = Date.newInstance(toDate.year() - 1, 4, 1);
                endDate = Date.newInstance(toDate.year(), 4, 1);
                fromDate2 = Date.newInstance(toDate.year() - 2, 4, 1);
                endDate1 = Date.newInstance(toDate.year()- 1, 4, 1);
            }

            //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql  2020/05/29 start
            
            if (toDate.month() >= 4) {
                yearWorkDay = 'WorkDate';
                yearWorkDay += String.valueOf(toDate.year() - 1867) + 'P__c';
                lastYearWorkDay = 'WorkDate';
                lastYearWorkDay += String.valueOf(toDate.year() - 1867 -1) + 'P__c';

            } else {
                yearWorkDay = 'WorkDate';
                yearWorkDay += String.valueOf(toDate.year() - 1 - 1867) + 'P__c';
                lastYearWorkDay = 'WorkDate';
                lastYearWorkDay += String.valueOf(toDate.year() - 2 - 1867) + 'P__c';
            }
            //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql  2020/05/29 end

        }
        //注释源代码
        // if (String.isBlank(yearField)) {
        if (String.isBlank(yearField)) {
            query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c,' + yearWorkDay + ' from User';
        } else {
            query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c, ' + yearField + ', ' + yearWorkDay + ' from User';
        }
        if (flag != null) {
            if (String.isBlank(yearField)) {
                query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c,';
                query += 'Last_financial_year_Jan__c,Last_financial_year_Feb__c,Last_financial_year_Mar__c,Last_financial_year_Apr__c,';
                query += 'Last_financial_year_May__c,Last_financial_year_June__c    ,Last_financial_year_July__c,Last_financial_year_Aug__c,';
                query += 'Last_financial_year_Sep__c,Last_financial_year_Oct__c ,Last_financial_year_Nov__c,Last_financial_year_Dec__c';
                query += ',' + yearWorkDay + ',' + lastYearWorkDay+ ' from User';
            } else {
                query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c,';
                query += 'Last_financial_year_Jan__c,Last_financial_year_Feb__c,Last_financial_year_Mar__c,Last_financial_year_Apr__c,';
                query += 'Last_financial_year_May__c,Last_financial_year_June__c    ,Last_financial_year_July__c,Last_financial_year_Aug__c,';
                query += 'Last_financial_year_Sep__c,Last_financial_year_Oct__c ,Last_financial_year_Nov__c,Last_financial_year_Dec__c';
                query += ',' + yearWorkDay + ',' + yearField + ',' + lastYearWorkDay+ ' from User';
            }
        } else {
            if (String.isBlank(yearField)) {
                query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c,';
                query += 'The_financial_year_Jan__c,The_financial_year_Feb__c,The_financial_year_Mar__c,The_financial_year_Apr__c,';
                query += 'The_financial_year_May__c,The_financial_year_June__c  ,The_financial_year_July__c,The_financial_year_Aug__c,';
                query += 'The_financial_year_Sep__c,The_financial_year_Oct__c   ,The_financial_year_Nov__c,The_financial_year_Dec__c';
                query += ',' + yearWorkDay + ',' + lastYearWorkDay+ ' from User';
            } else {
                query = 'select Id, Current_Daily_Report_Sum__c,Current_Daily_Report_Sum_work__c,Use_Start_Date__c,';
                query += 'The_financial_year_Jan__c,The_financial_year_Feb__c,The_financial_year_Mar__c,The_financial_year_Apr__c,';
                query += 'The_financial_year_May__c,The_financial_year_June__c  ,The_financial_year_July__c,The_financial_year_Aug__c,';
                query += 'The_financial_year_Sep__c,The_financial_year_Oct__c   ,The_financial_year_Nov__c,The_financial_year_Dec__c';
                query += ',' + yearWorkDay + ',' + yearField+ ',' + lastYearWorkDay + ' from User';
            }
        }
        //【委托】用户信息中增加工作日逻辑 逻辑1  更新本财年工作日数  精琢技术 wql  2020/05/29 end 
        if (String.isBlank(userId) == false) {
            query += ' where Id=\'' + userId + '\'';
        }
        system.debug('sql:' + query);
        return Database.getQueryLocator(query);
    }
    //2018/8/8 SWAG-B3D5PU 目前用户页面中已经有了一个“本期日报数”，累计的是所有的日报数，现在新建一个“本期日报数（工作日）”只累计工作日的日报数
    global void execute(Database.BatchableContext BC, List < sObject > scope) {
        List < User > userList = new List < User > ();
        userList = scope;
        List < AggregateResult > resultList = new List < AggregateResult > ();
        List < AggregateResult > resultList_work = new List < AggregateResult > ();
        List < Date > workDay = new List < Date > ();
        Date fromDate = null;
        Boolean nextYearFlag = false;

        if (toDate.month() >= 4) {
            fromDate = Date.newInstance(toDate.year(), 4, 1);
        } else {
            fromDate = Date.newInstance(toDate.year() - 1, 4, 1);
        }
        if (fromDate == toDate) {
            fromDate = Date.newInstance(toDate.year() - 1, 4, 1);
            nextYearFlag = true;
        }
        //用于存储最后需要更新的用户
        Map < Id, User > updateUserList = new Map < Id, User > ();
        Map < Id, User > userMap = new Map < Id, User > ();
        for (User u: userList) {
            userMap.put(u.Id, u);
        }
        //获取Olympus日历中的工作日
        List < OlympusCalendar__c > OlyCalendar = [select Date__c, IsWorkDay__c from OlympusCalendar__c where Date__c >= : fromDate and Date__c < : toDate];
        for (OlympusCalendar__c oly: OlyCalendar) {
            if (oly.IsWorkDay__c == 1) {
                workDay.add(oly.Date__c);
            }
        }
        system.debug('================' + workDay.size());
        resultList = [select COUNT(Id) dailyReportNum, Reporter__r.Id Reporter__c from Daily_Report__c
            where Reported_Date__c >= : fromDate and Reported_Date__c < : toDate
            and Reporter__r.Id in : userMap.keySet() // and (Status__c ='申請中' or Status__c ='承認')
            and(Status__c = '申請中'
                or Status__c = '承認') group by Reporter__r.Id
        ];
        //
        resultList_work = [select COUNT(Id) dailyReportNum, Reporter__r.Id Reporter__c from Daily_Report__c
            where Reported_Date__c = : workDay
            and Reporter__r.Id in : userMap.keySet()
            and(Status__c = '申請中'
                or Status__c = '承認') group by Reporter__r.Id
        ];
        /*resultWorkDateList = [];*/
        Map < Id, Integer > userNumMap = new Map < Id, Integer > ();
        Map < Id, Integer > userWorkNumMap = new Map < Id, Integer > ();
        if (resultList != null && resultList.size() > 0) {
            for (AggregateResult ar: resultList) {
                userNumMap.put((Id) ar.get('Reporter__c'), (Integer) ar.get('dailyReportNum'));
            }
        }
        if (resultList_work != null && resultList_work.size() > 0) {
            for (AggregateResult arw: resultList_work) {
                userWorkNumMap.put((Id) arw.get('Reporter__c'), (Integer) arw.get('dailyReportNum'));
            }
        }
        //该财年的奥林巴斯日历工作数
        list < Date > worklist = updateWorkDate_CountN(fromDate1, endDate);
        system.debug('奥林巴斯日历：' + worklist);
        //0 ：本财年 1：上财年 由于日历得1月份才更新 所以本财年 不会有123月日历
        Map < Id, Integer[]  > updateUserMap = updateWorkDate_CountM(0, worklist, toDate, fromDate1, endDate, userList, userMap);
        //上一财年的奥利巴斯日历工作数
        list < Date > lastWorklist = updateWorkDate_CountN(fromDate2, endDate1);
        system.debug('奥林巴斯日历上财年：' + lastWorklist);
        //0 ：本财年 1：上财年 由于日历得1月份才更新 所以本财年 不会有123月日历
        Map < Id, Integer[]  > updateUserLastMap = updateWorkDate_CountM(1, lastWorklist, toDate, fromDate2, endDate1, userList, userMap);
        List < User > updUsers = new List < User > ();
        system.debug('日报数：'+userNumMap);
        system.debug('用户：'+userMap);

        system.debug('用户：'+userMap);
        //更新本财年12月的工作日字段
        String [] FieldList   = new String[] {'Jan','Feb','Mar','Apr','May','June','July','Aug','Sep','Oct','Nov','Dec'};
        for (Id i: userMap.keySet()) {
            Integer drNum = userNumMap.get(i);
            Integer drwNum = userWorkNumMap.get(i);
            system.debug('本期日报数'+drNum);
            system.debug('本期日报数(工作日)'+drwNum);
            
            User us = userMap.get(i);
            //本财年的工作数
            Integer yearCount = 0;
            //上财年的工作数
            Integer lastYearCount = 0;
            //需要更新的该财年工作日数
            Integer[] userWorkDayCountList = updateUserMap.get(i);
            //需要更新的上财年的工作日数
            Integer[] userLastWorkDayCountList = updateUserLastMap.get(i);
            if (userWorkDayCountList != null) {
                for (Integer t = 0; t < userWorkDayCountList.size(); t++) {
                    if (userWorkDayCountList[t] != null) {
                        yearCount += userWorkDayCountList[t];
                    }
                }
            }
            if (userLastWorkDayCountList != null) {
                for (Integer l = 0; l < userLastWorkDayCountList.size(); l++) {
                    if (userLastWorkDayCountList[l] != null) {
                        lastYearCount += userLastWorkDayCountList[l];
                    }
                }
            }

            Boolean updFlag = false;
            if (us != null) {
                
                if (us.Current_Daily_Report_Sum_work__c != drwNum) {
                    us.Current_Daily_Report_Sum_work__c = drwNum;
                    system.debug('==drwNum==' + drwNum);
                    updFlag = true;
                }else if (drwNum == null){
                    us.Current_Daily_Report_Sum_work__c = 0;
                    updFlag = true;
                }
                if (us.Current_Daily_Report_Sum__c != drNum) {
                    us.Current_Daily_Report_Sum__c = drNum;
                    system.debug('==drNum==' + drNum);
                    updFlag = true;
                }else if (drNum == null){
                    us.Current_Daily_Report_Sum__c = 0;
                    updFlag = true;
                }

                //更新本财年的15几p工作日字段
                us.put(yearWorkDay, yearCount);
                //更新上财年的15几p工作日字段
                us.put(lastYearWorkDay, lastYearCount);
                for(Integer x =0;x<12;x++){
                    us.put('The_financial_year_'+FieldList[x]+'__c',userWorkDayCountList[x]);
                    us.put('Last_financial_year_'+FieldList[x]+'__c',userLastWorkDayCountList[x]);
                }
                updFlag = true;
                
                if (nextYearFlag) {
                    us.put(yearField, drNum);
                    updFlag = true;
                }
                if (updFlag) {
                    updUsers.add(us);
                }
            }
        }
        system.debug('更新的用户：' + updUsers);
        if (updUsers.size() > 0) {
            update updUsers;
        }
    }
    global void finish(Database.BatchableContext BC) {
        //2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  start
        if(!Test.isRunningTest() &&IsNeedExecute==true){
            //batch里调用下一个batch时，希望跟原有的Schedule里面传的条数保持一致
            Id execBTId = Database.executebatch(new UpdateUserTextColBatch(true),10);
        }
        //2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查 end

    }
    global static List < Date > updateWorkDate_CountN(Date fromDate1, Date endDate) {
        //用于存储本财年奥林巴斯日历的工作日
        List < Date > workDayNum = new List < Date > ();
        //用于存储每个用户的本财年的工作日数
        List < Date > workDayCount = new List < Date > ();
        //用于存储id 和 更新的工作日数
        Map < Id, Integer > userCountYearMap = new Map < Id, Integer > ();
        Map < Id, Integer[] > userCountMonthMap = new Map < Id, Integer[] > ();
        //根据上面不同财年的判断 获取不同财年的工作日
        List < OlympusCalendar__c > OlyCalendar = [select Date__c, IsWorkDay__c from OlympusCalendar__c where Date__c >= : fromDate1 and Date__c < : endDate];
        for (OlympusCalendar__c oly: OlyCalendar) {
            if (oly.IsWorkDay__c == 1) {
                workDayNum.add(oly.Date__c);
            }
        }
        return workDayNum;
    }
    //0 ：本财年 1：上财年 由于日历得1月份才更新 所以本财年 不会有123月日历
    global static Map < Id, Integer[] > updateWorkDate_CountM(Integer flag, List < Date > workDayNum, Date toDate, Date fromDate1, Date endDate1, List < User > userList, Map < Id, User > userMap) {
        
        
        //财年开始日
        Date startDate = fromDate1;
        //财年结束日
        Date endDate = endDate1;
        Boolean lastYear = false;
        //用于存储id 和 更新的工作日数
        Map < Id, Integer > userCountYearMap = new Map < Id, Integer > ();
        Map < Id, Integer[] > userCountMonthMap = new Map < Id, Integer[] > ();
        for (User u: userList) {
            //定义变量 用于存储当前月的用户工作日
            Integer Jan = 0;
            //定义变量 用于存储入职月份的工作日
            Integer Jan2 = 0;
            //定义相差的月份
            Integer monthDiff = 0;
            //当前是几月
            Integer month = 0;
            //开始月
            Integer monthFrom = 0;
            //本财年的工作数
            Integer yearCount = 0;
            if (u.Use_Start_Date__c != null) {
                //本财年用户入职月和当前月相差几个月份
                Integer userYear = u.Use_Start_Date__c.year();
                Integer userMonth = u.Use_Start_Date__c.month();
                //如果flag为空则说明要更新本财年的 要判断当前时间
                //同一年 月份差直接 当前月-入职月
                //先判断是否该财年入职  else则是该财年以前入职的
                if ((startDate.year() == userYear && userMonth >= 4) || (endDate.year() == userYear && userMonth < 4)) {
                    //说明是该财年上半年 入职的
                    if (startDate.year() == userYear || endDate.year() == userYear) {
                        //说明上半年入职的  则直接当前月-入职月
                        monthDiff = 12 - userMonth;
                    } else if (endDate.year() == toDate.year() && startDate.year() == userYear) {
                        //说明当前时间到了下半年，入职是上半年
                        monthDiff = 12 - userMonth + 4;
                    }
                    monthFrom = userMonth;
                } else {
                    if (startDate.year() >= userYear) {
                        //说明上财年入职的 该财年已4月份开始计算
                        monthDiff = 12;
                        monthFrom = 0;
                    } else if (endDate.year() == userYear) {
                        //说明还该财年还没入职
                    }
                }
            }
            //用于定义每个财年每个月的工作日
            Integer[] monthWorkDayList = new Integer[12];
            //每个用户每年的工作日 通过两部分构成 第一部分： 入职月  + 第二部分：该财年剩余月
            //循环遍历日历
            /*计算的是每年的工作日 按月拆分的工作日数  精琢技术 wql  2020/06/02 start   第二部分 ：该财年12月*/
            for (Integer i = 1; i <= 12; i++) {
                Integer countMonth = 0;
                for (Date d: workDayNum) {
                    if (d.month() == i) {
                        countMonth++;
                    }
                }
                monthWorkDayList[i - 1] = countMonth;
            }
            for (Date d: workDayNum) {
            /*计算的是入职该用户的工作日   精琢技术 wql  2020/06/03 start   第一部分：入职月*/
                    if (monthFrom != 0) {
                        if (d.month() == monthFrom) {
                            if (d >= u.Use_Start_Date__c) {
                                Jan2++;
                            }
                        }
                    }
                    /*计算的是入职该用户的工作日   精琢技术 wql  2020/06/03 end*/
                }
            system.debug('第一次更新每财年每月：' + monthWorkDayList);
            /*计算的是每年的工作日 按月拆分的工作日数  精琢技术 wql  2020/06/02 end*/
            system.debug('入职月工作日：' + Jan2);
            system.debug('入职月：' + monthFrom + '----' + '差：' + monthDiff);
            //存放每个用户的每月工作日
            Integer[] monthList = monthWorkDate_CountM(flag, monthFrom, monthDiff, Jan2, monthWorkDayList);
            if (u.Use_Start_Date__c > endDate) {
                //说明该财年还未入职，则工作日数为0
                Integer[] newWordList = new Integer[] {0,0,0,0,0,0,0,0,0,0,0,0};
                monthList = newWordList;
            }
            system.debug('最后更新每财年每月：' + monthList);
            if (monthList != null) {
                for (Integer i = 0; i < monthList.size(); i++) {
                    if (monthList[i] != null) {
                        yearCount += monthList[i];
                    }
                }
            }
            userCountYearMap.put((Id) u.Id, (Integer) yearCount);
            userCountMonthMap.put((Id) u.Id, (Integer[]) monthList);
        }
            return userCountMonthMap;
        }
    /*month ：当前月; monthFrom:入职月 ;monthDiff: 中间月; Jan : 当前月工作日 ; Jan2 : 入职月工作日  monthWorkDayList ：每财年每个月的工作日*/
    global static Integer[] monthWorkDate_CountM(Integer flag, Integer monthFrom, Integer monthDiff, Integer Jan2, Integer[] monthWorkDayList) {
        //flag 0 ：本财年 1：上财年 由于日历得1月份才更新 所以本财年 不会有123月日历
        //定义最后返回的用户十二月工作日
        Integer[] userWorkDayList = new Integer[] {0,0,0,0,0,0,0,0,0,0,0,0};
        if (monthFrom != 0) {
            //②计算中间月的工作日
            if (monthDiff == 0) {
                //则说明是这个月入职的
                //①先算第一部分 入职月的工作日
                userWorkDayList[monthFrom - 1] = Jan2;
                //如果是上财年的123月 则奥林巴斯日历已经更新
                if(flag == 1){
                    Integer b = 4;
                    for (Integer j = 1; j <= b - 1; j++) {
                        userWorkDayList[j - 1] = monthWorkDayList[j - 1];
                    }
                }
            } else {
                //则说明入职到现在一定有中间整月的情况
                //①先算第一部分 入职月的工作日
                userWorkDayList[monthFrom - 1] = Jan2;
                //计算有中间整月的情况 比如 4，5，6,7,8,9,10,11,12     1,2,3
                Integer a = 12 - monthFrom;
                Integer b = 4;
                for (Integer i = 0; i < a; i++) {
                    userWorkDayList[monthFrom + i] = monthWorkDayList[monthFrom + i];
                }
                for (Integer j = 1; j <= b - 1; j++) {
                    userWorkDayList[j - 1] = monthWorkDayList[j - 1];
                }
            }
        } else {
            //以前财年入职的，更新该财年 全部工作日
            for (Integer i = 0; i < 12; i++) {
                userWorkDayList[i] = monthWorkDayList[i];
            }
        }
        //返回用户12月的工作日的数组  依次为1月、2月...12月
        return userWorkDayList;
    }
}