/**
 * Created by T on 2020/5/14.
 */

public with sharing class MonthEndAutoJudgeBatch implements Database.Batchable<SObject>, Database.Stateful {
    public final List<Id> TEST_ID = null;
    private BatchIF_Log__c iflog;

    // Special_Apply_Reason__c 临时存储数据用 20200916 Gzw update

    // 当前年月
    private Integer yearInteger = Date.today().year();
    private Integer monInteger = Date.today().month();

    public MonthEndAutoJudgeBatch(){
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'MonthEndAutoJudgeBatch';
        iflog.Log__c = 'MonthEndAutoJudgeBatch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }
    /**
     *
     *
     * @param testId 测试的Id 集合
     * @param flag  用于筛选数据的条件
     */
    public MonthEndAutoJudgeBatch(List<Id> testId) {
        TEST_ID = testId;
        iflog = new BatchIF_Log__c();
        iflog.Type__c = 'MonthEndAutoJudgeBatch';
        iflog.Log__c = 'MonthEndAutoJudgeBatch start\n';
        iflog.ErrorLog__c = '';
        insert iflog;
    }

    /**
     * startには、queryを実行、引合全件
     */
    public Database.QueryLocator start(Database.BatchableContext BC) {
        String staSql = 'SELECT id,Name,Owner__c,CreatedDate,Special_Apply_Reason__c,Opportunity__c,';
        staSql += ' Shipping_Scheduled_Date_For_Report__c,DeliveryDate__c,DeliveryStatus__c,isManualApprove__c,';
        staSql += ' PaymentStatus__c,Monthly_forecast_shipping__c,NM_forecast_shipping__c,FirstApproveDate__c,';
        staSql += ' End_User_contract__c,ContractReceivedDate__c,LastDay_of_MonthDelivery__c FROM Statu_Achievements__c';
        // 判断条件,测试跳过
        String  condition =  ' where (( OverviewStatus__c <> \'无效合同\' and (OverviewStatus__c <> \'订单完成\' or (SS_backorderID__c <> null and OverviewStatus_SS_IsEqual__c = false))) or Forecast_Equal__c=false)  ';
        // 手动审批的注残跳过
        condition += ' and isManualApprove__c = false  ';
        // 特殊对应中关于最后一天发货的情况
        // LastDay_of_MonthDelivery__c

        // 当前月的第一个工作日 +1便于做判断
        Date firstWorkDate = getFirstWorkDayOfMonth().addDays(1);
        // 当前月的最后五个工作日中最小的那天
        Date minOfLastFiveWorkDate = getLastWorkDay();

        // 付款状态
        List<String> paymentStatus = new List<String>();
        paymentStatus.add('尾款完成');
        paymentStatus.add('100%预付完成');
        paymentStatus.add('不需付款');
        paymentStatus.add('尾款支付');
        // Gzw 20200831  追加新状态
        paymentStatus.add('100%预付款');

        // 排除预测发货日为null的数据
        // 第一个工作日记录的预测对象的注残
        // 最后五个工作日前,提交用户合同并付全款
        // Gzw 20200831  去掉预测发货日条件 start
        // condition += ' and Shipping_Scheduled_Date_For_Report__c <> null' +
        // Gzw 20200831  去掉预测发货日条件 end
                // 由14.收到合同日 改为 18.付全款日期或 17.预付款日期
                // '   AND ContractReceivedDate__c < :minOfLastFiveWorkDate' +
        condition += '   and PaymentJudge__c < :minOfLastFiveWorkDate ' +
                '   and End_User_contract__c = \'已提交\'' +
                '   and PaymentStatus__c IN :paymentStatus' +
                '   and ForecastAccuracyObject__c = True ' +
                '   and CreatedDate < :firstWorkDate ';

        if (TEST_ID != null && TEST_ID.size() > 0) {
            staSql += ' where id in :TEST_ID';
        } else {
            staSql += condition;
        }

        // System.debug('staSql=' + staSql);
        return Database.getQueryLocator(staSql);
    }

    public void execute(Database.BatchableContext BC, List<Statu_Achievements__c> staList) {
        Savepoint sp = Database.setSavepoint();
        // 获取本月1号
        Date toDate = Date.today();
        Date mon1stDate = Date.newInstance(toDate.year(), toDate.month(), 1);
        try {
            // 需要更新的数据
            List<Statu_Achievements__c> updateList = new List<Statu_Achievements__c>();
            // 只要标记为true,代表修改过注残,添加到需要更新的集合中
            Boolean flag = false;
            // 迭代所有数据
            for (Statu_Achievements__c sa : staList) {
                // if (String.isBlank(sa.Special_Apply_Reason__c)) {
                    sa.Special_Apply_Reason__c = '';
                // }    
                // 有本月发货预测的标记
                if ('本月发货预测'.equals(sa.Monthly_forecast_shipping__c)) {
                    // 本月没有发货
                    // 如果助理勾选了最后一天发货，如果有本月发预测，系统不修改预测
                    // Gzw 20200831  删除本月发货预测 条件扩展  
                    // DeliveryDate__c == null ——》 DeliveryDate__c == null || DeliveryDate__c < 本月
                    // 去掉 部分交付
                    // if (!('部分交付'.equals(sa.DeliveryStatus__c)) && !('已完全交付'.equals(sa.DeliveryStatus__c))
                    if (!('已完全交付'.equals(sa.DeliveryStatus__c))
                        && (sa.DeliveryDate__c == null ||  sa.DeliveryDate__c < mon1stDate )&& sa.LastDay_of_MonthDelivery__c == false) {
                        sa.Monthly_forecast_shipping__c = '删除本月发货预测';
                        iflog.Log__c += 'Name: '+sa.Name+' 删除本月发货预测\n';
                        // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 start
                        // sa.Special_Apply_Reason__c += ' 删除本月发货预测';
                        // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 end
                        flag = true;
                    }

                }

                if (!String.isBlank(sa.DeliveryStatus__c) && !('未交付'.equals(sa.DeliveryStatus__c))) {
                    // 已发货后说明有发货日期,查看是否本月发货 如果是本月发货添加发货标记
                    // 如果助理勾选了最后一天发货,添加本月发货
                    // Gzw 202008902 注残预测标识：需要增加看初审日是本月之前的。
                    // 获取本月1号
                    // Date toDate = Date.today();
                    // Date mon1stDate = Date.newInstance(toDate.year(), toDate.month(), 1);
                    if (((sa.DeliveryDate__c != null && sa.DeliveryDate__c.year() == yearInteger && sa.DeliveryDate__c.month() == monInteger) || sa.LastDay_of_MonthDelivery__c) && sa.FirstApproveDate__c < mon1stDate ) {
                        // 添加本月发货预测
                        if (String.isBlank(sa.Monthly_forecast_shipping__c)){
                            sa.Monthly_forecast_shipping__c = '新增本月发货预测';
                            iflog.Log__c += 'Name: '+sa.Name+' 新增本月发货预测\n';
                            // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 start
                            sa.Special_Apply_Reason__c = ' 提前完成备货';
                            // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 end
                            flag = true;
                        }
                    }
                }

                // 有次月发货预测标记
                if ('次月发货预测'.equals(sa.NM_forecast_shipping__c)) {
                    // 并且在本月完成全部发货
                    if (('已完全交付'.equals(sa.DeliveryStatus__c) && sa.DeliveryDate__c.year() == yearInteger && sa.DeliveryDate__c.month() == monInteger) || sa.LastDay_of_MonthDelivery__c) {
                        sa.NM_forecast_shipping__c = '删除次月发货预测';
                        iflog.Log__c += 'Name: '+sa.Name+' 删除次月发货预测\n';
                        // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 start
                        // sa.Special_Apply_Reason__c += ' 删除次月发货预测';
                        // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 end
                        flag = true;
                    }
                }

                // 如果到本月跑Batch时还没有全部发货 : 当月全部发货为否,并且符合次月预测时间,添加次月预测标记
                // Gzw 20200821 注残次月预测标识：需要增加看初审日是本月之前的。
                if (!('已完全交付'.equals(sa.DeliveryStatus__c))) {
                    // 如果月份是12月
                    // 次月为 下一年的一月份
                    // 如果没有次月发货预测的标记 判断是否符合条件
                    // 如果助理勾选了，如果有本月发预测，系统不修改预测
                    if (isNMForecastShipping(sa)) {
                        System.debug('----------------- ' + isNMForecastShipping(sa));
                        if (String.isBlank(sa.NM_forecast_shipping__c) && !(String.isNotBlank(sa.Monthly_forecast_shipping__c) && sa.LastDay_of_MonthDelivery__c)) {
                            sa.NM_forecast_shipping__c = '新增次月发货预测';
                            // System.debug('添加次月');
                            iflog.Log__c += 'Name: '+sa.Name+' 新增次月发货预测\n';
                            // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 start
                            sa.Special_Apply_Reason__c = ' 货期推迟';
                            // WLIG-BT26AE Gzw 新增预测时，添加理由 20200916 end
                            flag = true;
                        }
                    }
                }
                if(flag){
                    System.debug('1111111111111 ' + sa.Special_Apply_Reason__c);
                    updateList.add(sa);
                    flag = false;
                }
            }

            List<OpportunitySpecialApply__c> newOpportunitySpecialApply = new List<OpportunitySpecialApply__c>();
            // 将直接修改注残 改为 新建询价注残特殊对应审批
            for (Statu_Achievements__c upSa : updateList){
                System.debug('222222222222 ' + upSa.Special_Apply_Reason__c);
                OpportunitySpecialApply__c spec = new OpportunitySpecialApply__c();
                // spec.Status__c = '草案中';
                spec.Status__c = '已批准';
                //spec.Apply_Content__c = String.isBlank(upSa.Monthly_forecast_shipping__c) ? '删除本月发货预测' : '新增本月发货预测';
                //spec.NMApply_Content_c__c = String.isBlank(upSa.NM_forecast_shipping__c) ? '删除次月发货预测' : '新增次月发货预测';
                if (upSa.Monthly_forecast_shipping__c == '删除本月发货预测' || upSa.Monthly_forecast_shipping__c == '新增本月发货预测') {
                    spec.Apply_Content__c = upSa.Monthly_forecast_shipping__c;
                }
                if (upSa.NM_forecast_shipping__c == '删除次月发货预测' || upSa.NM_forecast_shipping__c == '新增次月发货预测') {
                    spec.NMApply_Content_c__c = upSa.NM_forecast_shipping__c;
                }
                spec.Apply_Reason__c = String.isBlank(upSa.Special_Apply_Reason__c) ? '其他' : upSa.Special_Apply_Reason__c;
                if (spec.Apply_Reason__c == '其他') {
                    spec.Apply_Memo__c = upSa.Monthly_forecast_shipping__c + upSa.NM_forecast_shipping__c;
                }
                spec.Approval_Date__c = Date.today();
                spec.Achievements__c = upSa.Id;
                spec.Opportunity__c = upSa.Opportunity__c;
                spec.RecordTypeId = Schema.SObjectType.OpportunitySpecialApply__c.getRecordTypeInfosByDeveloperName().get('AchievementsRecordType').getRecordTypeId();
                newOpportunitySpecialApply.add(spec);
            }
            insert newOpportunitySpecialApply;
        }catch (Exception e){
            iflog.ErrorLog__c += e.getMessage();
            Database.rollback(sp);
        }
       
        // Database.update(updateList);
    }

    public void finish(Database.BatchableContext BC) {
        iflog.Log__c += 'MonthEndAutoJudgeBatch 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;
    }

    /**
     * 判断是否是 次月预测
     *
     * @param sa
     *
     * @return
     */
    // Gzw 20200821 注残次月预测标识：需要增加看初审日是本月之前的。
    public boolean isNMForecastShipping(Statu_Achievements__c sa) {
        // 获取本月1号
        Date toDate = Date.today();
        Date mon1stDate = Date.newInstance(toDate.year(), toDate.month(), 1);
        // mon1stDate = mon1stDate.addMonths(1);
        System.debug('+++++++++++++++++++ ' + sa.FirstApproveDate__c + mon1stDate);
        return (((sa.Shipping_Scheduled_Date_For_Report__c.year() == yearInteger && sa.Shipping_Scheduled_Date_For_Report__c.month() == monInteger + 1) ||
                (sa.Shipping_Scheduled_Date_For_Report__c.year() == yearInteger + 1 && sa.Shipping_Scheduled_Date_For_Report__c.month() == 1 && monInteger == 12)) && sa.FirstApproveDate__c < mon1stDate);
    }

    /**
     * 获取当前月份的第一个工作日
     *
     * @return
     */
    public Date getFirstWorkDayOfMonth() {
        // 获取当前月份的第一天
        Date firstDayOfMonth = Date.today().toStartOfMonth();
        // 将月份推到下一个月
        Date nextMonth = Date.newInstance(firstDayOfMonth.year(), firstDayOfMonth.month() + 1, 1);
        // 获取当前月份最后一天
        // System.debug('lastDay:' + nextMonth.addDays(-1));

        Date lastDayOfMonth = nextMonth.addDays(-1);
        // 此表会维护一个工作日的日历 其中排除掉了周末及节假日 此处通过排序加limit 1 只拿到第一个工作日
        List<OlympusCalendar__c> olympusCalendarDate = [
                Select Date__c
                From OlympusCalendar__c
                Where Date__c >= :firstDayOfMonth
                And Date__c <= :lastDayOfMonth
                And IsWorkDay__c = 1
                ORDER BY Date__c
                LIMIT 1
        ];
        Date firstWorkDayOfMonth = null;
        if (olympusCalendarDate.size() > 0) {
             firstWorkDayOfMonth = olympusCalendarDate.get(0).Date__c;
        }
        // System.debug('firstWorkDayOfMonth' + firstWorkDayOfMonth);
        return firstWorkDayOfMonth;
    }

    /**
     * 获取最后五个工作日中的最小的那天
     *
     * @return
     */
    public Date getLastWorkDay() {
        // 获取当前月份的第一天
        Date firstDayOfMonth = Date.today().toStartOfMonth();
        // 将月份推到下一个月
        Date nextMonth = Date.newInstance(firstDayOfMonth.year(), firstDayOfMonth.month() + 1, 1);
        // 获取当前月份最后一天
        // System.debug('lastDay:' + nextMonth.addDays(-1));
        Date lastDayOfMonth = nextMonth.addDays(-1);
        // 此表会维护一个工作日的日历 其中排除掉了周末及节假日 此处通过排序加limit 5 拿到最后五个工作日
        List<OlympusCalendar__c> olympusCalendarDates = [
                Select Date__c
                From OlympusCalendar__c
                Where Date__c >= :firstDayOfMonth
                And Date__c <= :lastDayOfMonth
                And IsWorkDay__c = 1
                ORDER BY Date__c DESC
                LIMIT 5
        ];
        // System.debug('List<OlympusCalendar__c> :' + olympusCalendarDates);
        Date result;
        if (olympusCalendarDates.size() > 0) {
            result = olympusCalendarDates.get(olympusCalendarDates.size() - 1).Date__c;
            // System.debug('result' + result);
        }
        return result;
    }

}