package org.zstack.compute.host;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cascade.AbstractAsyncCascadeExtension;
import org.zstack.core.cascade.CascadeAction;
import org.zstack.core.cascade.CascadeConstant;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SQL;
import org.zstack.core.db.SimpleQuery;
import org.zstack.header.core.Completion;
import org.zstack.header.host.HostInventory;
import org.zstack.header.host.HostNumaNodeVO;
import org.zstack.header.host.HostNumaNodeVO_;
import org.zstack.header.host.HostVO;
import org.zstack.header.vm.VmInstanceNumaNodeVO;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.function.Function;
import org.zstack.utils.logging.CLogger;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class HostNumaNodeCascadeExtension extends AbstractAsyncCascadeExtension {
    private static final CLogger logger = Utils.getLogger(HostNumaNodeCascadeExtension.class);


    @Autowired
    private DatabaseFacade dbf;

    @Override
    public void asyncCascade(CascadeAction action, Completion completion) {
        if (action.isActionCode(CascadeConstant.DELETION_DELETE_CODE) ||
                action.isActionCode(CascadeConstant.DELETION_CLEANUP_CODE) ||
                action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)) {
            handleDeletion(action, completion);
        } else {
            completion.success();
        }
    }

    private void handleDeletion(CascadeAction action, Completion completion) {
        try {
            final List<String> hostUuids = hostFromAction(action);
            if (hostUuids != null && !hostUuids.isEmpty()) {
                hostUuids.forEach(this::deleteHostNumaNodes);
            }
        } catch (NullPointerException e) {
            logger.warn(e.getMessage());
        } finally {
            completion.success();
        }
    }

    private void deleteHostNumaNodes(String hostUuid) {
        SimpleQuery<HostNumaNodeVO> nodesQuery = dbf.createQuery(HostNumaNodeVO.class);
        nodesQuery.add(HostNumaNodeVO_.hostUuid, SimpleQuery.Op.EQ, hostUuid);
        List<HostNumaNodeVO> nodes = nodesQuery.list();
        if (!nodes.isEmpty()) {
            for (HostNumaNodeVO node: nodes) {
                dbf.remove(node);
            }
        }
    }

    private List<String> hostFromAction(CascadeAction action) {
        List<String> hostUuids = new ArrayList<>();
        if (HostVO.class.getSimpleName().equals(action.getParentIssuer())) {
            List<HostInventory> hosts = action.getParentIssuerContext();
            hostUuids = CollectionUtils.transformToList(hosts, new Function<String, HostInventory>() {
                @Override
                public String call(HostInventory arg) {
                    return arg.getUuid();
                }
            });
        }
        return hostUuids;
    }

    @Override
    public List<String> getEdgeNames() {
        return Arrays.asList(HostVO.class.getSimpleName());
    }

    @Override
    public String getCascadeResourceName() {
        return HostNumaNodeVO.class.getSimpleName();
    }

    @Override
    public CascadeAction createActionForChildResource(CascadeAction action) {
        return null;
    }
}

@@ -1315,24 +1315,29 @@
 ION_
-CLEANUP
+FORCE_DELETE
 _CODE)
- %7C%7C
+) %7B
 %0A   
@@ -1337,36 +1337,87 @@
 ) %7B%0A            
-    
+handleDeletion(action, completion);%0A        %7D else if (
 action.isActionC
@@ -1441,36 +1441,31 @@
 nt.DELETION_
-FORCE_DELETE
+CLEANUP
 _CODE)) %7B%0A  
@@ -1480,32 +1480,39 @@
   handleDeletion
+CleanUp
 (action, complet
@@ -1577,32 +1577,436 @@
        %7D%0A    %7D%0A%0A
+    private void handleDeletionCleanUp(CascadeAction action, Completion completion) %7B%0A        cleanUpDeletedHostNumaNodes();%0A        completion.success();%0A    %7D%0A%0A    private void cleanUpDeletedHostNumaNodes() %7B%0A        String sql = %22select d.id from HostNumaNodeVO d where d.hostUuid not in (select v.uuid from HostVO v)%22;%0A        dbf.hardDeleteCollectionSelectedBySQL(sql, HostNumaNodeVO.class);%0A    %7D%0A%0A
     private void

add deletionCleanUp for HostVnumaNode