public without sharing class InventoryDetailHandler extends Oly_TriggerHandler {
    private Map<Id, Inventory_Detail__c> newMap;
    private Map<Id, Inventory_Detail__c> oldMap;
    private List<Inventory_Detail__c> newList;
    private List<Inventory_Detail__c> oldList;

    private static Set<Id> updatedAsset = new Set<Id>();
    private static Map<Id, Asset> needUpdateAsset = new Map<Id, Asset>();

    public InventoryDetailHandler() {
        this.newMap = (Map<Id, Inventory_Detail__c>) Trigger.newMap;
        this.oldMap = (Map<Id, Inventory_Detail__c>) Trigger.oldMap;
        this.newList = (List<Inventory_Detail__c>) Trigger.new;
        this.oldList = (List<Inventory_Detail__c>) Trigger.old;
    }

    protected override void beforeInsert() {

    }

    protected override void beforeUpdate() {
        needUpdateAsset = new Map<Id, Asset>();
        beforeSetValue();
    }

    protected override void afterUpdate() {
        setFrozenQuantity();
        CheckOnetoOneLink();
        setAsset();
        // OLY_OCM-663 汇总子明细的盘点状态到主明细中。未来如果盘点表画面可能需要更多过滤方式的话，考虑修改Batch在主明细中追加Asset单位的数量等字段
        checkInventoryStatus();
        if (needUpdateAsset.isEmpty() == false) {
            update needUpdateAsset.values();
        }
    }

    private void beforeSetValue() {
        for (Inventory_Detail__c nObj : newList) {
            Inventory_Detail__c oObj;
            if (Trigger.isUpdate) {
                oObj = oldMap.get(nObj.Id);
            }
            if (oObj != null
                    && oObj.Auto_Lost_item_giveup__c == false
                    && nObj.Auto_Lost_item_giveup__c == true) {
                nObj.Auto_Giveup_Time__c = Datetime.now();
            }
        }
    }

    private void setFrozenQuantity() {
        Map<Id, Decimal> assetCount = new Map<Id, Decimal>();
        Map<Id, Decimal> assetCount2 = new Map<Id, Decimal>();
        Map<String, Decimal> otoLinkCount = new Map<String, Decimal>();
        Set<Id> astSet = new Set<Id>();
        for (Inventory_Detail__c nObj : newList) {
            Inventory_Detail__c oObj = oldMap.get(nObj.Id);
            if (oObj.Inventory_Count__c == nObj.Inventory_Count__c) continue;
            Decimal oldDeviation = oObj.Inventory_Count__c == null ? 0 :oObj.Inventory_Deviation__c;
            Decimal newDeviation = nObj.Inventory_Count__c == null ? 0 :nObj.Inventory_Deviation__c;

            //盘点盘亏数
            //实盘数不能大于应盘数，盘盈不能反映到冻结里
            if (oldDeviation < 0 || newDeviation < 0) {
                Decimal count;
                Decimal oto_count;
                if (oldDeviation >= 0) {
                    count = 0 - newDeviation;
                } else if (newDeviation >= 0) {
                    count = oldDeviation;
                } else {
                    count = oldDeviation - newDeviation;
                }
                oto_count = count;
                if (assetCount.containsKey(nObj.Asset__c)) {
                    count += assetCount.get(nObj.Asset__c);
                }
                assetCount.put(nObj.Asset__c, count);
                //一对一附属品盘亏冻结数
                if (nObj.Fixture_OneToOne_Link__c != null) {
                    if (otoLinkCount.containsKey(nObj.Fixture_OneToOne_Link__c)) {
                        oto_count += otoLinkCount.get(nObj.Fixture_OneToOne_Link__c);
                    }
                    otoLinkCount.put(nObj.Fixture_OneToOne_Link__c, oto_count);
                }
                astSet.add(nObj.Asset__c);
            }

            //盘点盘盈数
            //盘亏不能反映到盘盈数里
            if (oldDeviation > 0 || newDeviation > 0) {
                Decimal count;
                if (oldDeviation <= 0) {
                    count = newDeviation;
                } else if (newDeviation <= 0) {
                    count = 0 - oldDeviation;
                } else {
                    count = newDeviation - oldDeviation;
                }
                if (assetCount2.containsKey(nObj.Asset__c)) {
                    count += assetCount2.get(nObj.Asset__c);
                }
                assetCount2.put(nObj.Asset__c, count);
                astSet.add(nObj.Asset__c);
            }
        }

        //一对一附属品盘亏数处理
        if (otoLinkCount.isEmpty() == false) {
            List<Fixture_OneToOne_Link__c> otoList = [select Id, Inventory_Frozen_Quantity__c from Fixture_OneToOne_Link__c where Id in :otoLinkCount.keySet()];
            for (Fixture_OneToOne_Link__c oto : otoList) {
                if (oto.Inventory_Frozen_Quantity__c == null) oto.Inventory_Frozen_Quantity__c = 0;
                oto.Inventory_Frozen_Quantity__c += otoLinkCount.get(oto.Id);
            }
            update otoList;
        }

        List<Asset> updateList = new List<Asset>();
        List<Inventory_Detail__c> updateIdList = new List<Inventory_Detail__c>();
        if (astSet.isEmpty() == false) {
            List<Asset> astList = [select Id, Inventory_Frozen_Quantity__c, Inventory_Profit_Quantity__c from asset where Id in :astSet];
            List<Inventory_Detail__c> idList = [select Id, Sync_Asset_Frozen_Quantity__c, Sync_Asset_Profit_Quantity__c, Asset__c from Inventory_Detail__c where Asset__c in :astSet and Sync_Asset_Record_Flag__c = true];
            for (Asset ast : astList) {
                if (ast.Inventory_Frozen_Quantity__c == null) ast.Inventory_Frozen_Quantity__c = 0;
                if (ast.Inventory_Profit_Quantity__c == null) ast.Inventory_Profit_Quantity__c = 0;
                if (assetCount.containsKey(ast.Id)) {
                    ast.Inventory_Frozen_Quantity__c += assetCount.get(ast.Id);
                }
                if (assetCount2.containsKey(ast.Id)) {
                    ast.Inventory_Profit_Quantity__c += assetCount2.get(ast.Id);
                }
                
                updateList.add(ast);
            }

            for (Inventory_Detail__c idl : idList) {
                if (idl.Sync_Asset_Frozen_Quantity__c == null) idl.Sync_Asset_Frozen_Quantity__c = 0;
                if (idl.Sync_Asset_Profit_Quantity__c == null) idl.Sync_Asset_Profit_Quantity__c = 0;
                if (assetCount.containsKey(idl.Asset__c)) {
                    idl.Sync_Asset_Frozen_Quantity__c += assetCount.get(idl.Asset__c);
                }
                if (assetCount2.containsKey(idl.Asset__c)) {
                    idl.Sync_Asset_Profit_Quantity__c += assetCount2.get(idl.Asset__c);
                }
                
                updateIdList.add(idl);
            }
            update updateList;
            update updateIdList;
        }
    }

    private void setAsset() {
        for (Inventory_Detail__c nObj : newList) {
            Inventory_Detail__c oObj = oldMap.get(nObj.Id);
            if (oObj.Auto_Lost_item_giveup__c == false
                    && nObj.Auto_Lost_item_giveup__c == true
                    && !updatedAsset.contains(nObj.Asset__c)) {
                Asset ass = new Asset(Id = nObj.Asset__c);
                if (nObj.Appended_Inventory_Frozen_Quantity_F__c > 0) {
                    ass.Abandoned_Inventory__c = nObj.Abandoned_Inventory_F__c + nObj.Appended_Inventory_Frozen_Quantity_F__c;
                }
                updatedAsset.add(nObj.Asset__c);
                ass.Appended_Inventory_Frozen_Quantity__c = 0;
                needUpdateAsset.put(nObj.Asset__c, ass);
            }
        }
    }

    private void CheckOnetoOneLink() {
        Set<Id> otoIds = new Set<Id>();
        for (Inventory_Detail__c nObj : newList) {
            Inventory_Detail__c oObj;
            if (Trigger.isUpdate) {
                oObj = oldMap.get(nObj.Id);
            }
            if (oObj != null 
                    && nObj.Fixture_OneToOne_Link__c != null
                    && oObj.Auto_Lost_item_giveup__c == false
                    && nObj.Auto_Lost_item_giveup__c == true
                    && nObj.Manage_type__c == FixtureUtil.managetypeMap.get(FixtureUtil.Managetype.Shu_Liang_Guan_Li)) {
                otoIds.add(nObj.Fixture_OneToOne_Link__c);
            }
        }
        
        if (otoIds.size() > 0) {
            List<Fixture_OneToOne_Link__c> delList = new List<Fixture_OneToOne_Link__c>();
            List<Fixture_OneToOne_Link__c> updateList = new List<Fixture_OneToOne_Link__c>();
            List<Fixture_OneToOne_Link__c> otoList = [select Id, Inventory_Frozen_Quantity__c, Quantity__c from Fixture_OneToOne_Link__c where Id in :otoIds];
            for (Fixture_OneToOne_Link__c oto : otoList) {
                if (oto.Inventory_Frozen_Quantity__c >= oto.Quantity__c) {
                    delList.add(oto);
                }
                else if(oto.Inventory_Frozen_Quantity__c > 0) {
                    oto.Quantity__c -= oto.Inventory_Frozen_Quantity__c;
                    oto.Inventory_Frozen_Quantity__c = 0;
                    updateList.add(oto);
                }
            }
            if(!delList.isEmpty()) {
                delete delList;
            }
            if(!updateList.isEmpty()) {
                update updateList;
            }
        }
    }

    private void checkInventoryStatus() {
        Set<Id> assetIds = new Set<Id>();
        for (Inventory_Detail__c nObj : newList) {
            Inventory_Detail__c oObj;
            if (Trigger.isUpdate) {
                oObj = oldMap.get(nObj.Id);
            }
            if (oObj != null 
                    && oObj.Inventory_Time__c == null
                    && nObj.Inventory_Time__c != null) {
                assetIds.add(nObj.Asset__c);
            }
        }

        if (assetIds.size() > 0) {
            AggregateResult[] results = [select count(Id) cnt, Asset__c 
                                            from Inventory_Detail__c 
                                            where Asset__c in :assetIds and Asset_Status__c in ('在库','冻结') and Amount__c <> 0 and Inventory_Time__c = null
                                            AND Inventory_Header__r.Inventory_Status__c = '盘点中'
                                            group by Asset__c];
            for (AggregateResult ar : results) {
                if(Integer.valueOf(ar.get('cnt')) > 0) {
                    assetIds.remove((Id)String.valueOf(ar.get('Asset__c')));
                }
            }

            List<Inventory_Detail__c> updateDetails = [select Id, Asset_Inventory_Flg__c 
                                                            from Inventory_Detail__c 
                                                            where Asset__c in :assetIds and Sync_Asset_Record_Flag__c = true];
            if (updateDetails.size() > 0) {
                for (Inventory_Detail__c upd : updateDetails) {
                    upd.Asset_Inventory_Flg__c = true;
                }

                update updateDetails;
            }
        }
    }
}