global without sharing class AssetMaintainManualBatch implements Database.Batchable<sObject>, Database.Stateful {
    global Id AssetMaintainHeaderId;
    global List<String> errorList = new List<String>();
    global List<String> warningList = new List<String>();
    global Integer allCount = 0;
    global Integer doneCount = 0;
    global Boolean needCheck;
    global Operation op;
    global Integer round; // 跑几次
    global Set<Id> abandonFailedIdSet = new Set<Id>(); // 废弃失败的assetId
    global enum Operation {
        FROZEN, // 提交后冻结
        UNFROZEN, // 取消，驳回，回调时解冻
        PROCESS, // 更新asset
        ABANDON // 废弃
    }
    // 一次只跑一个维护单
    /**
    @description
    @param AssetMaintainHeaderId 维护单Id
    @param needCheck 是否要在batch中做数量检查
    */
    global AssetMaintainManualBatch(Id AssetMaintainHeaderId, Boolean needCheck) {
        this.AssetMaintainHeaderId = AssetMaintainHeaderId;
        this.needCheck = needCheck;
        this.op = Operation.PROCESS;
        this.round = 4; // 默认总共跑4次
    }

    /**
    @description
    @param AssetMaintainHeaderId 维护单Id
    @param needCheck 是否要在batch中做数量检查
    @param op 为哪种操作而做检查
    */
    global AssetMaintainManualBatch(Id AssetMaintainHeaderId, Boolean needCheck, Operation op) {
        this.AssetMaintainHeaderId = AssetMaintainHeaderId;
        this.needCheck = needCheck;
        this.op = op;
        this.round = 4; // 默认总共跑4次
    }
    /**
    @description
    @param AssetMaintainHeaderId 维护单Id
    @param needCheck 是否要在batch中做数量检查
    @param op 为哪种操作而做检查
    @param round 最多共跑几次，其中第1次必跑，如果因为lock没跑成功就接着跑，直到总次数达到round
    */
    global AssetMaintainManualBatch(Id AssetMaintainHeaderId, Boolean needCheck, Operation op, Integer round) {
        this.AssetMaintainHeaderId = AssetMaintainHeaderId;
        this.needCheck = needCheck;
        this.op = op;
        this.round = round;
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {

        String query = 'SELECT Id'
                    + ' , Fixture_Model_No__c'
                    + '  , MaintainType__c'
                    + '  , MaintainCount__c'
                    + '  , DisconnectCount__c'
                    + '  , AbandonCount__c'
                    + '  , Asset__c'
                    + '  , Batch_Status__c'
                    + '  , Is_OneToOne_Accessory__c'
                    + '  , OneToOne_Main__c'
                 + '  FROM AssetMaintainDetail__c'
                 + '  WHERE AssetMaintainHeader__c = :AssetMaintainHeaderId'
                 + '  AND Batch_Status__c != \'完成\'';
        // 只有废弃才会把能维护的先维护掉
        if (this.op != Operation.ABANDON && this.needCheck) {
            LogBean bean = AssetMaintainManualBatch.checkAllDetailAndAsset(this.AssetMaintainHeaderId, this.op);
            List<String> errList = bean.errorList;
            System.debug(errList);
            if (errList.size() > 0) {
                query += ' AND Id = null';
                errorList = errList;
            }
            warningList = bean.warningList;
        }
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<AssetMaintainDetail__c> amdList1) {
        Set<Id> amhSet = new Set<Id>();
        // for(AssetMaintainHeader__c amh:amhList){
        //     amhSet.add(amh.Id);
        // }
        List<AssetMaintainDetail__c> amdList = [SELECT Id
                                                     , Fixture_Model_No__c
                                                     , MaintainType__c
                                                     , MaintainCount__c
                                                     , DisconnectCount__c
                                                     , AbandonCount__c
                                                     , Asset__c
                                                     , Batch_Status__c
                                                     , Is_OneToOne_Accessory__c
                                                     , OneToOne_Main__c
                                                     , AssetMaintainHeader__r.Submit_Time__c
                                                     , AssetMaintainHeader__r.Approved_Time__c
                                                  FROM AssetMaintainDetail__c
                                                  WHERE Id =: amdList1
                                                  AND Batch_Status__c!='完成'
                                                  FOR UPDATE];
        if(amdList.size() == 0){
            return;
        }
        allCount += amdList.size();
        Savepoint sp = Database.setSavepoint();
        try {

            Set<Id> assetIdSet = new Set<Id>();
            for(AssetMaintainDetail__c amd: amdList){
                assetIdSet.add(amd.Asset__c);
            }
            Map<Id, Asset> assetMap = new Map<Id, Asset>([SELECT Id
                                                               , Abandoned_Inventory__c
                                                               , Internal_Asset_number__c
                                                               , Fixture_Model_No_F__c
                                                               , Abandoned_RealThing__c
                                                               , Frozen_Quantity__c
                                                               , You_Xiao_Ku_Cun__c
                                                               , Manage_type__c
                                                               , In_wh_Fu_Shu_Pin_You_Xiao_Ku_Cun_Sum__c
                                                               , Ji_Zhong_Guan_Li_Ku_Cun__c
                                                               , Quantity
                                                               , Main_OneToOne__c
                                                               , Consumable_Guaranteen_end__c
                                                               , MaintainCount_For_Processing__c
                                                            FROM Asset
                                                           WHERE Id IN: assetIdSet
                                                             FOR UPDATE]);
            List<Fixture_OneToOne_Link__c> linkList = [SELECT Id
                                                    , Quantity__c
                                                    , Main_Asset__c
                                                    , Accessory_Asset__c
                                                 FROM Fixture_OneToOne_Link__c
                                                WHERE Main_Asset__c IN:assetMap.keySet()
                                                   OR Accessory_Asset__c IN:assetMap.keySet()
                                                  FOR UPDATE
                                            ];
            Map<Id, List<Fixture_OneToOne_Link__c>> assetLinksMap = new Map<Id, List<Fixture_OneToOne_Link__c>>();
            for(Fixture_OneToOne_Link__c link:linkList){
                if(!assetLinksMap.containsKey(link.Main_Asset__c)){
                    assetLinksMap.put(link.Main_Asset__c, new List<Fixture_OneToOne_Link__c>());
                }
                if(!assetLinksMap.containsKey(link.Accessory_Asset__c)){
                    assetLinksMap.put(link.Accessory_Asset__c, new List<Fixture_OneToOne_Link__c>());
                }
                assetLinksMap.get(link.Main_Asset__c).add(link);
                assetLinksMap.get(link.Accessory_Asset__c).add(link);
            }
            List<String> checkErrorList = new List<String> ();
            if(this.needCheck){
                checkErrorList = checkAllDetailAndAsset(amdList, assetMap, assetLinksMap, amdList[0].MaintainType__c, this.op, this.abandonFailedIdSet).errorList;
            }
            if(checkErrorList.size() > 0) {
                // 只有废弃才会把能维护的先维护掉
                if(this.op != Operation.ABANDON) {
                    throw new ControllerUtil.myException(String.join(checkErrorList, '\n'));
                }
                else {
                    errorList.addAll(checkErrorList);
                }
            }
            Map<Id, Fixture_OneToOne_Link__c> updateLinks = new Map<Id, Fixture_OneToOne_Link__c>();
            Map<Id, Fixture_OneToOne_Link__c> deleteLinks = new Map<Id, Fixture_OneToOne_Link__c>();
            List<AssetMaintainDetail__c> amdUpdateList = new List<AssetMaintainDetail__c>();
            Datetime now = System.now();
            for(AssetMaintainDetail__c amd: amdList){
                Asset ass = assetMap.get(amd.Asset__c);
                switch on amd.MaintainType__c{
                    when '断念找回(断念取消)'{
                        ass.Giveup_Return__c = '断念找回';
                        ass.Abandoned_Inventory__c = intValueOf(ass.Abandoned_Inventory__c) - intValueOf(amd.MaintainCount__c);
                        ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                        ass.Status = '使用中';
                        amd.Batch_Status__c = '完成';
                        amd.MaintainedTime__c = now;
                    }
                    when '断念找回(重新登录)'{
                        ass.Quantity = intValueOf(ass.Quantity) + intValueOf(amd.MaintainCount__c);
                        ass.ChangeQuantityReason__c = '断念找回';
                        ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                        ass.Status = '使用中';
                        amd.Batch_Status__c = '完成';
                        amd.MaintainedTime__c = now;
                    }
                    when '解冻' {
                        ass.Frozen_Quantity__c = intValueOf(ass.Frozen_Quantity__c) - intValueOf(amd.MaintainCount__c);
                        ass.Status = '使用中';
                        ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                        ass.Freeze_sign__c = ass.Frozen_Quantity__c >= ass.Quantity;
                        amd.Batch_Status__c = '完成';
                        amd.MaintainedTime__c = now;
                    }
                    when '冻结'{
                        ass.Frozen_Quantity__c = intValueOf(ass.Frozen_Quantity__c) + intValueOf(amd.MaintainCount__c);
                        ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                        // 个体 一对一主体 删掉和所有附属品的link
                        if(ass.Manage_type__c=='个体管理' && ass.Main_OneToOne__c
                            && assetLinksMap.containsKey(ass.Id)){
                            ass.Fixture_OneToOne_Link__c = null;
                            ass.Main_OneToOne__c = false;
                            for (Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)) {
                                if (link.Main_Asset__c == ass.Id) {
                                    deleteLinks.put(link.Id, link);
                                }
                            }
                        }
                        // 个体 一对一附属品 删掉和主体的link
                        if(ass.Manage_type__c=='个体管理' && assetLinksMap.containsKey(ass.Id)){
                            ass.Fixture_OneToOne_Link__c = null;
                            for (Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)) {
                                if (link.Accessory_Asset__c == ass.Id) {
                                    deleteLinks.put(link.Id, link);
                                }
                            }
                        }

                        // 数量 一对一附属品 link里减去断开数，减到0就删掉
                        if(ass.Manage_type__c=='数量管理' && assetLinksMap.containsKey(ass.Id)
                            && intValueOf(amd.DisconnectCount__c) > 0){
                            for(Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)){
                                if(link.Accessory_Asset__c == ass.Id
                                    && link.Main_Asset__c == amd.OneToOne_Main__c){
                                    link.Quantity__c = intValueOf(link.Quantity__c) - intValueOf(amd.DisconnectCount__c);
                                    if(link.Quantity__c <= 0){
                                        deleteLinks.put(link.Id, link);
                                        if (updateLinks.containsKey(link.Id)) {
                                            updateLinks.remove(link.Id);
                                        }
                                    }
                                    else{
                                        updateLinks.put(link.Id, link);
                                    }
                                }
                            }
                        }
                        ass.Status = '使用中';
                        ass.Freeze_sign__c = ass.Frozen_Quantity__c >= ass.Quantity;
                        amd.Batch_Status__c = '完成';
                        amd.MaintainedTime__c = now;
                    }
                    when '实物报废'{
                        if(this.op == Operation.UNFROZEN){
                            ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                        }
                        // 批准时操作
                        else if(this.op == Operation.PROCESS && amd.Batch_Status__c == '未处理'){
                            ass.Abandoned_RealThing__c = intValueOf(ass.Abandoned_RealThing__c) + intValueOf(amd.MaintainCount__c);
                            ass.MaintainCount_For_Processing__c = intValueOf(ass.MaintainCount_For_Processing__c) - intValueOf(amd.MaintainCount__c) ;
                            // 个体 一对一主体 删除和所有附属品的link
                            if(ass.Manage_type__c=='个体管理' && ass.Main_OneToOne__c
                                && assetLinksMap.containsKey(ass.Id)){
                                ass.Fixture_OneToOne_Link__c = null;
                                ass.Main_OneToOne__c = false;
                                for(Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)){
                                    if(link.Main_Asset__c == ass.Id){
                                        deleteLinks.put(link.Id, link);
                                    }
                                }
                            }
                            // 个体 一对一附属品 删掉和主体的link
                            if(ass.Manage_type__c=='个体管理' && assetLinksMap.containsKey(ass.Id)){
                                ass.Fixture_OneToOne_Link__c = null;
                                for(Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)){
                                    if(link.Accessory_Asset__c == ass.Id){
                                        deleteLinks.put(link.Id, link);
                                    }
                                }
                            }

                            // 数量 一对一附属品 link里减去断开数，减到0删掉
                            if(ass.Manage_type__c=='数量管理' && assetLinksMap.containsKey(ass.Id)){
                                for(Fixture_OneToOne_Link__c link :assetLinksMap.get(ass.Id)){
                                    if(link.Accessory_Asset__c == ass.Id && link.Main_Asset__c == amd.OneToOne_Main__c){
                                        link.Quantity__c = intValueOf(link.Quantity__c) - intValueOf(amd.DisconnectCount__c);
                                        if(link.Quantity__c <= 0) {
                                            deleteLinks.put(link.Id, link);
                                            if(updateLinks.containsKey(link.Id)){
                                                updateLinks.remove(link.Id);
                                            }
                                        }
                                        else{
                                            updateLinks.put(link.Id, link);
                                        }
                                    }
                                }
                            }
                            if(ass.Abandoned_RealThing__c >= ass.Quantity){
                                ass.Status = '待报废';
                            }
                            else{
                                ass.Status = '使用中';
                            }
                            amd.Batch_Status__c = '处理中';
                            amd.MaintainedTime__c = now;
                        }
                        // 废弃时的操作
                        else if(this.op == Operation.ABANDON && amd.Batch_Status__c == '处理中') {
                            if (this.abandonFailedIdSet.contains(amd.Asset__c)) {
                                continue;
                            }
                            ass.Abandoned_RealThing__c = intValueOf(ass.Abandoned_RealThing__c) - intValueOf(amd.AbandonCount__c);
                            ass.Quantity = intValueOf(ass.Quantity) - intValueOf(amd.AbandonCount__c);
                            ass.ChangeQuantityReason__c = '废弃';

                            if (ass.Manage_type__c == '个体管理') {
                                ass.Status = ass.Quantity <= 0 ? FixtureUtil.assetStatusMap.get(FixtureUtil.AssetStatus.Fei_Qi.ordinal()) : '使用中';
                            }
                            else{
                                if(ass.Consumable_Guaranteen_end__c == null || ass.Consumable_Guaranteen_end__c>System.today()){
                                    ass.Status = '使用中';
                                }
                                else {
                                    ass.Status = ass.Quantity <= 0 ? FixtureUtil.assetStatusMap.get(FixtureUtil.AssetStatus.Fei_Qi.ordinal()) : '使用中';
                                }
                            }
                            amd.Batch_Status__c = '完成';
                            amd.AbandonedTime__c = now;
                        }
                    }
                }
                amdUpdateList.add(amd);
            }
            if (!amdUpdateList.isEmpty()) {
                update amdUpdateList;
                // 只有维修单都维护完了才会更新维护单状态
                List<AssetMaintainDetail__c> amdListf = [SELECT Id
                                                     , Fixture_Model_No__c
                                                     , MaintainType__c
                                                     , MaintainCount__c
                                                     , DisconnectCount__c
                                                     , AbandonCount__c
                                                     , Asset__c
                                                     , OneToOne_Main__c
                                                     , AssetMaintainHeader__r.Status__c
                                                FROM AssetMaintainDetail__c
                                                WHERE AssetMaintainHeader__c =: AssetMaintainHeaderId
                                                AND Batch_Status__c != '完成'];
                if (amdUpdateList.size() == amdList.size() && amdListf.size() == 0) {
                    if(amdUpdateList[0].Batch_Status__c == '完成'){
                        AssetMaintainHeader__c ah = new AssetMaintainHeader__c(Id = this.AssetMaintainHeaderId);
                        ah.Status__c = '已完成';
                        update ah;
                    }
                }
            }
            if (!deleteLinks.isEmpty()) {
                List<Fixture_OneToOne_Link__c> deleteList = [
                    SELECT Id
                    FROM Fixture_OneToOne_Link__c
                    WHERE Id IN: deleteLinks.keySet()
                ];
                if (!deleteList.isEmpty()) {
                    delete deleteList;
                }
            }
            if (!updateLinks.isEmpty()) {
                update updateLinks.values();
            }
            if (!assetMap.isEmpty()) {
                update assetMap.values();
            }
            doneCount += amdUpdateList.size();
        }
        catch (Exception e) {
            Database.rollback(sp);
            for(String errorMsg: e.getMessage().split('\n')) {
                errorList.add(errorMsg + '\n' + e.getStackTraceString());
            }
            System.debug(LoggingLevel.ERROR, e.getMessage() + '\n' + e.getStackTraceString());
        }

    }

    global void finish(Database.BatchableContext BC) {
        this.round -= 1;
        // 当所有错误都是lock引起时才要重跑
        Boolean lockFailure = errorList.size() > 0;
        for(String errorMsg :this.errorList){
            if (!errorMsg.contains('Record Currently Unavailable')
                && !errorMsg.contains('记录当前不可用')
                && !errorMsg.contains('レコードは現在利用できません')) {
                lockFailure = false;
                break;
            }
        }
        if (lockFailure && this.round > 0 && allCount > 0) {
            AssetMaintainManualBatch bat = new AssetMaintainManualBatch(this.AssetMaintainHeaderId, this.needCheck, this.op, this.round);
            Database.executeBatch(bat, Integer.valueOf(System.Label.AssetMaintainManualBatchSize));
        }
        else {
            BatchEmailUtil be = new BatchEmailUtil();
            String[] toList = new String[]{};
            String[] ccList = new String[]{};
            User u = [SELECT Id,Email from User where Id = :UserInfo.getUserId()];
            toList.add(u.Email);
            for (Consum_Apply_Meta__mdt camd : [SELECT Id
                        , Key__c
                        , ValueLong__c
                     FROM Consum_Apply_Meta__mdt
                    WHERE Package__c = 'AssetMaintainManualBatch'
                      AND Key__c = 'ErrorMailAddress'
                    ORDER BY Key__c]) {
                for(String email:camd.ValueLong__c.split(',')){
                    if (!toList.contains(email)) {
                        ccList.add(email);
                    }
                }
            }
            List<AssetMaintainHeader__c> amhList = [SELECT Name
                                                         , MaintainType__c
                                                         , Batch_Processing__c
                                            FROM AssetMaintainHeader__c
                                            WHERE Id =:this.AssetMaintainHeaderId];
            String title = '';
            String text = '';
            switch on this.op{
                when PROCESS{
                    text = '保有设备相关字段修改';
                }
                when FROZEN{
                    text = '保有设备冻结';
                }
                when UNFROZEN{
                    text = '保有设备解冻';
                }
                when ABANDON{
                    text = '保有设备废弃';
                }
            }

            if(!amhList.isEmpty()){
                title += 'Batch 数据维护单 ' + amhList[0].Name + ' ' +amhList[0].MaintainType__c + ' ';
                if(amhList[0].Batch_Processing__c) {
                    amhList[0].Batch_Processing__c = false;
                    update amhList[0];
                }
            }
            if (allCount != doneCount || errorList.size() > 0) {
                for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName
                        FROM OrgWideEmailAddress
                        WHERE DisplayName like 'BatchNotify']) {
                    ccList.add(tmpEmailObj.Address);
                }
                for (Consum_Apply_Meta__mdt camd : [SELECT Id
                            , Key__c
                            , ValueLong__c
                         FROM Consum_Apply_Meta__mdt
                        WHERE Package__c = 'AssetMaintainAutoBatch'
                          AND Key__c = 'ErrorMailAddress'
                        ORDER BY Key__c]) {

                    for(String email:camd.ValueLong__c.split(',')) {
                        if (!toList.contains(email) && !ccList.contains(email)) {
                            ccList.add(email);
                        }
                    }
                }
                text += '失败\n'+String.join(this.errorList, '\n');
                be.failedMail(toList, ccList, title, text, allCount, doneCount, errorList.size());
                be.send();
            }
            else if (this.op != Operation.ABANDON){ // 废弃成功时有workflow发邮件，这里不用发
                text += '成功\n';
                for(String log : warningList) {
                    text += log + '\n';
                }
                be.successMail(toList, ccList, title, allCount, text);
                be.send();
            }
        }

    }

    /**
    @description 检查维护单下的明细中数量是否合法
    @param AssetMaintainHeaderId 维护单Id
    @param op 为哪种操作而做检查
    @return 错误列表
    */
    public static LogBean checkAllDetailAndAsset(Id AssetMaintainHeaderId, Operation op){
        List<AssetMaintainDetail__c> amdList = [SELECT Id
                                                     , Fixture_Model_No__c
                                                     , MaintainType__c
                                                     , MaintainCount__c
                                                     , DisconnectCount__c
                                                     , AbandonCount__c
                                                     , Asset__c
                                                     , OneToOne_Main__c
                                                     , AssetMaintainHeader__r.Status__c
                                                     , AssetMaintainHeader__r.Submit_Time__c
                                                     , AssetMaintainHeader__r.Approved_Time__c
                                                FROM AssetMaintainDetail__c
                                                WHERE AssetMaintainHeader__c =: AssetMaintainHeaderId
                                                AND Batch_Status__c != '完成'];
        if(amdList.size() > 0){
            Set<Id> assetIdSet = new Set<Id>();
            for(AssetMaintainDetail__c amd:amdList){
                assetIdSet.add(amd.Asset__c);
            }
            return checkAllDetailAndAsset(amdList, assetIdSet, amdList[0].MaintainType__c, op);
        }
        LogBean lb = new LogBean();
        lb.errorList.add('没有维护明细');
        return lb;
    }

    /**
    @description 检查维护单明细数量是否合法
    @param amdList 维护单明细列表
    @param assetIdSet 维护单明细对应的AssetId Set
    @param maintainType 维护类型
    @param op 为哪种操作而做检查
    @return 错误列表
    */
    public static LogBean checkAllDetailAndAsset(List<AssetMaintainDetail__c> amdList, Set<Id> assetIdSet, String maintainType, Operation op){
        Map<Id, Asset> assetMap = new Map<Id, Asset>([SELECT Id
                                                           , Abandoned_Inventory__c
                                                           , Internal_Asset_number__c
                                                           , Fixture_Model_No_F__c
                                                           , Abandoned_RealThing__c
                                                           , Frozen_Quantity__c
                                                           , You_Xiao_Ku_Cun__c
                                                           , Manage_type__c
                                                           , In_wh_Fu_Shu_Pin_You_Xiao_Ku_Cun_Sum__c
                                                           , Ji_Zhong_Guan_Li_Ku_Cun__c
                                                           , Quantity
                                                           , MaintainCount_For_Processing__c
                                                           , Main_OneToOne__c
                                                        FROM Asset
                                                       WHERE Id IN: assetIdSet
                                                         FOR UPDATE]);
        List<Fixture_OneToOne_Link__c> linkList = [SELECT Id
                                                        , Quantity__c
                                                        , Main_Asset__c
                                                        , Accessory_Asset__c
                                                     FROM Fixture_OneToOne_Link__c
                                                    WHERE Main_Asset__c IN:assetMap.keySet()
                                                       OR Accessory_Asset__c IN:assetMap.keySet()
                                                      FOR UPDATE
                                                ];
        Map<Id, List<Fixture_OneToOne_Link__c>> assetLinksMap = new Map<Id, List<Fixture_OneToOne_Link__c>>();
        for(Fixture_OneToOne_Link__c link:linkList){
            if(!assetLinksMap.containsKey(link.Main_Asset__c)){
                assetLinksMap.put(link.Main_Asset__c, new List<Fixture_OneToOne_Link__c>());
            }
            if(!assetLinksMap.containsKey(link.Accessory_Asset__c)){
                assetLinksMap.put(link.Accessory_Asset__c, new List<Fixture_OneToOne_Link__c>());
            }
            assetLinksMap.get(link.Main_Asset__c).add(link);
            assetLinksMap.get(link.Accessory_Asset__c).add(link);
        }
        return checkAllDetailAndAsset(amdList, assetMap, assetLinksMap, maintainType, op);
    }

    public static LogBean checkAllDetailAndAsset(List<AssetMaintainDetail__c> amdList, Map<Id, Asset> assetMap,
                                                        Map<Id, List<Fixture_OneToOne_Link__c>> assetLinksMap,
                                                        String maintainType, Operation op) {
        return checkAllDetailAndAsset(amdList, assetMap, assetLinksMap, maintainType, op, new Set<Id>());
    }
    /**
    @description 检查维护单明细数量是否合法
    @param amdList 维护单明细列表
    @param assetMap 维护单明细对应的Map <AssetId, Asset>
    @param assetLinksMap 保有设备相关的一对一link <AssetId, link列表>
    @param maintainType 维护类型
    @param op 为哪种操作而做检查
    @param abandonFailedIdSet 储存检查不过的assetId，用作返回值
    @return 错误列表
    */
    public static LogBean checkAllDetailAndAsset(List<AssetMaintainDetail__c> amdList, Map<Id, Asset> assetMap,
                                                        Map<Id, List<Fixture_OneToOne_Link__c>> assetLinksMap,
                                                        String maintainType, Operation op,
                                                        Set<Id> abandonFailedIdSet) {
        List<String> errorList = new List<String>();
        List<String> warningList = new List<String>();
        // 总维护数
        Map<Id, Integer> assetMaintainMap = new Map<Id, Integer>();
        // 总废弃数
        Map<Id, Integer> assetAbandonMap = new Map<Id, Integer>();
        // 总断开数
        Map<String, Integer> linkDisconnectMap = new Map<String, Integer>();
        // 收集主体设备Id，如果主体和附属品在同一单中，附属品的断开数会被无视
        Set<Id> mainIdSet = new Set<Id>();
        // 需要忽略检查的主体
        Set<Id> ignoreMainIdSet = new Set<Id>();
        Datetime submitTime = null;
        Datetime approveTime = null;
        // 重新查出需要更新的Asset
        for(AssetMaintainDetail__c amd:amdList){
            if(amd.AssetMaintainHeader__r.Submit_Time__c != null && submitTime == null) {
                submitTime = amd.AssetMaintainHeader__r.Submit_Time__c;
            }
            if(amd.AssetMaintainHeader__r.Approved_Time__c != null && approveTime == null) {
                approveTime = amd.AssetMaintainHeader__r.Approved_Time__c;
            }
            if(!assetMap.containsKey(amd.Asset__c)){
                errorList.add(amd.Fixture_Model_No__c + '保有设备不存在或不可以更新');
            }
            if(assetMap.get(amd.Asset__c).Main_OneToOne__c) {
                mainIdSet.add(amd.Asset__c);
            }
            Integer t = assetMaintainMap.containsKey(amd.Asset__c)?assetMaintainMap.get(amd.Asset__c):0;
            assetMaintainMap.put(amd.Asset__c, t + intValueOf(amd.MaintainCount__c));

            t = assetAbandonMap.containsKey(amd.Asset__c)?assetAbandonMap.get(amd.Asset__c):0;
            assetAbandonMap.put(amd.Asset__c, t + intValueOf(amd.AbandonCount__c));
        }
        for(AssetMaintainDetail__c amd:amdList){
            // 检查一对一主体是否与明细的asset有link
            if (op != Operation.ABANDON && amd.OneToOne_Main__c != null) {
                Boolean assetMainAvailable = false;
                if (assetLinksMap.containsKey(amd.Asset__c)) {
                    for (Fixture_OneToOne_Link__c link:assetLinksMap.get(amd.Asset__c)) {
                        if (amd.OneToOne_Main__c == link.Main_Asset__c) {
                            assetMainAvailable = true;
                            break;
                        }
                    }
                }
                if (!assetMainAvailable) {
                    // 实物报废审批后，link不存在就不做检查
                    if(approveTime != null && submitTime != null && maintainType == '实物报废') {
                        warningList.add(amd.Fixture_Model_No__c + '与【一对一主体选择】的link已断开，不做link检查');
                        ignoreMainIdSet.add(amd.OneToOne_Main__c);
                    }
                    else {
                        errorList.add(amd.Fixture_Model_No__c + '【一对一主体选择】不正确');
                    }
                }
            }
            // 一对一附属品Asset可能同时对不同的主体有不同的断开数
            if(!ignoreMainIdSet.contains(amd.OneToOne_Main__c)) {
                String linkName = amd.Asset__c + ':' + amd.OneToOne_Main__c;
                Integer t = linkDisconnectMap.containsKey(linkName)?linkDisconnectMap.get(linkName):0;
                linkDisconnectMap.put(linkName, t + intValueOf(amd.DisconnectCount__c));
            }
        }

        for(Id assetId:assetMap.keySet()){
            Asset ass = assetMap.get(assetId);
            Integer maintainCount = assetMaintainMap.containsKey(assetId)?assetMaintainMap.get(assetId):0;
            Integer abandonCount = assetAbandonMap.containsKey(assetId)?assetAbandonMap.get(assetId):0;

            switch on maintainType{
                when '断念找回(断念取消)'{
                    // 维护数量<=待废弃数(丢失/盘亏)
                    if(maintainCount > intValueOf(ass.Abandoned_Inventory__c)){
                        errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】不可超过【待废弃数(丢失/盘亏)】');
                    }
                    // 必须是非固定资产
                    if(String.isNotBlank(ass.Internal_Asset_number__c)){
                        errorList.add(ass.Fixture_Model_No_F__c + '固定资产不可断念找回');
                    }
                }
                when '断念找回(重新登录)'{
                    // 必须是非固定资产
                    if(String.isNotBlank(ass.Internal_Asset_number__c)){
                        errorList.add(ass.Fixture_Model_No_F__c + '固定资产不可断念找回');
                    }
                }
                when '冻结'{
                    // 维护数量<=有效库存
                    if(maintainCount > ass.You_Xiao_Ku_Cun__c){
                        errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】不可超过【有效库存】');
                    }

                    Integer allDisconnectCount = 0;
                    // 一对一附属品：断开数量<=主体选择对应的一对一Link表.一对一附属品管理数量
                    if(assetLinksMap.containsKey(assetId)) {
                        for(Fixture_OneToOne_Link__c link : assetLinksMap.get(assetId)){
                            String linkName = link.Accessory_Asset__c + ':' + link.Main_Asset__c;
                            Integer disconnectCount = 0;
                            // 主体的断开数恒为0
                            if(mainIdSet.contains(assetId)) {
                                disconnectCount = 0;
                            }
                            // 附属品所连的主体在同一单里，断开数为全部
                            else if (mainIdSet.contains(link.Main_Asset__c)) {
                                disconnectCount = intValueOf(link.Quantity__c);
                            }
                            // 主体不在同一单里，则断开数来自用户填写
                            else {
                                disconnectCount = linkDisconnectMap.containsKey(linkName)?linkDisconnectMap.get(linkName):0;
                                if(disconnectCount > link.Quantity__c){
                                    errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过一对一Link的【数量】');
                                }
                            }
                            allDisconnectCount += disconnectCount;
                        }
                    }
                    // 维护数量-断开数量<=集中管理库存
                    if(maintainCount - allDisconnectCount > ass.Ji_Zhong_Guan_Li_Ku_Cun__c) {
                        errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】-【断开数量】不可超过【集中管理库存】');
                    }
                    // 断开数量<=上架的附属品有效库存_合计
                    if(allDisconnectCount > ass.In_wh_Fu_Shu_Pin_You_Xiao_Ku_Cun_Sum__c){
                        errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过【上架的附属品有效库存_合计】');
                    }
                }
                when '解冻'{
                    // 维护数量<=冻结数
                    if(maintainCount > intValueOf(ass.Frozen_Quantity__c)) {
                        errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】不可超过【冻结数】');
                    }
                }
                when '实物报废'{
                    Integer allDisconnectCount = 0;
                    // 提交申请时检查
                    if(op == Operation.FROZEN){
                        // 维护数量<=有效库存
                        if(maintainCount > ass.You_Xiao_Ku_Cun__c){
                            errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】不可超过【有效库存】');
                        }
                        // 一对一附属品：断开数量<=主体选择对应的一对一Link表.一对一附属品管理数量
                        if(assetLinksMap.containsKey(assetId)) {
                            for(Fixture_OneToOne_Link__c link : assetLinksMap.get(assetId)){
                                String linkName = link.Accessory_Asset__c + ':' + link.Main_Asset__c;
                                Integer disconnectCount = 0;
                                // 主体的断开数恒为0
                                if(mainIdSet.contains(assetId)) {
                                    disconnectCount = 0;
                                }
                                // 附属品所连的主体在同一单里，断开数为全部
                                else if (mainIdSet.contains(link.Main_Asset__c)) {
                                    disconnectCount = intValueOf(link.Quantity__c);
                                }
                                // 主体不在同一单里，则断开数来自用户填写
                                else {
                                    disconnectCount = linkDisconnectMap.containsKey(linkName)?linkDisconnectMap.get(linkName):0;
                                    if(disconnectCount > link.Quantity__c){
                                        errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过一对一Link的【数量】');
                                    }
                                }
                                allDisconnectCount += disconnectCount;
                            }
                        }
                        // 维护数量-断开数量<=集中管理库存
                        if(maintainCount - allDisconnectCount>ass.Ji_Zhong_Guan_Li_Ku_Cun__c){
                            errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】-【断开数量】不可超过【集中管理库存】');
                        }
                        // 断开数量<=上架的附属品有效库存_合计
                        if(allDisconnectCount > ass.In_wh_Fu_Shu_Pin_You_Xiao_Ku_Cun_Sum__c){
                            errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过【上架的附属品有效库存_合计】');
                        }
                    }
                    // 提交申请后【有效库存】和【集中管理库存】会移到【待处理维护数】里，批准时检查要把【待处理维护数】算进来
                    if(op == Operation.PROCESS){
                        // 维护数量<=有效库存
                        if(maintainCount > ass.You_Xiao_Ku_Cun__c + intValueOf(ass.MaintainCount_For_Processing__c)) {
                            errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】不可超过【有效库存】+【待处理维护数】');
                        }
                        // 一对一附属品：断开数量<=主体选择对应的一对一Link表.一对一附属品管理数量
                        if(assetLinksMap.containsKey(assetId) && !ass.Main_OneToOne__c){
                            for(Fixture_OneToOne_Link__c link : assetLinksMap.get(assetId)){
                                String linkName = link.Accessory_Asset__c + ':' + link.Main_Asset__c;
                                Integer disconnectCount = 0;
                                // 主体的断开数恒为0
                                if(mainIdSet.contains(assetId)) {
                                    disconnectCount = 0;
                                }
                                // 附属品所连的主体在同一单里，断开数为全部
                                else if (mainIdSet.contains(link.Main_Asset__c)) {
                                    disconnectCount = intValueOf(link.Quantity__c);
                                }
                                // 主体不在同一单里，则断开数来自用户填写
                                else {
                                    disconnectCount = linkDisconnectMap.containsKey(linkName)?linkDisconnectMap.get(linkName):0;
                                    if(disconnectCount > link.Quantity__c){
                                        errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过一对一Link的【数量】');
                                    }
                                }
                                allDisconnectCount += disconnectCount;
                            }
                        }
                        // 维护数量-断开数量<=集中管理库存
                        if(maintainCount - allDisconnectCount > ass.Ji_Zhong_Guan_Li_Ku_Cun__c + intValueOf(ass.MaintainCount_For_Processing__c)) {
                            errorList.add(ass.Fixture_Model_No_F__c + '【维护数量】-【断开数量】不可超过【集中管理库存】+【报废冻结数】');
                        }
                        // 断开数量<=上架的附属品有效库存_合计
                        if(allDisconnectCount > ass.In_wh_Fu_Shu_Pin_You_Xiao_Ku_Cun_Sum__c){
                            errorList.add(ass.Fixture_Model_No_F__c + '【断开数量】不可超过【上架的附属品有效库存_合计】');
                        }
                    }
                    // 废弃时检查
                    if(op == Operation.ABANDON) {
                        // 废弃数量<=待废弃数(实物)
                        if(abandonCount > intValueOf(ass.Abandoned_RealThing__c)) {
                            errorList.add(ass.Fixture_Model_No_F__c + '【废弃数量】不可超过【待废弃数(实物)】');
                            abandonFailedIdSet.add(ass.Id);
                        }
                    }
                    // 所有节点都检查 废弃数量 <= 数量
                    if(abandonCount>ass.Quantity){
                        errorList.add(ass.Fixture_Model_No_F__c + '【废弃数量】不可超过【数量】');
                        abandonFailedIdSet.add(ass.Id);
                    }
                    // 废弃数量 <= 维护数量 + 待废弃数(实物)
                    if (abandonCount > maintainCount + intValueOf(ass.Abandoned_RealThing__c)) {
                        errorList.add(ass.Fixture_Model_No_F__c + '【废弃数量】不可超过【维护数量】+【待废弃数(实物)】');
                        abandonFailedIdSet.add(ass.Id);
                    }
                }
            }
        }
        return new LogBean(errorList, warningList);
    }
    private static Integer intValueOf(Decimal d) {
        if(d == null || d < 0) {
            return 0;
        }
        return Integer.valueOf(d);
    }
    public class LogBean {
        public List<String> errorList;
        public List<String> warningList;
        public LogBean() {
            this.errorList = new List<String>();
            this.warningList = new List<String>();
        }
        public LogBean(List<String> errors, List<String> warnings) {
            this.errorList = errors;
            this.warningList = warnings;
        }
    }
}