package org.zstack.network.service.virtualrouter.vip;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.SimpleQuery.Op;
import org.zstack.header.core.Completion;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowRollback;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.network.service.vip.*;
import org.zstack.network.service.virtualrouter.VirtualRouterConstant;
import org.zstack.network.service.virtualrouter.VirtualRouterVmInventory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VirtualRouterSyncVipFlow implements Flow {
    @Autowired
    protected DatabaseFacade dbf;
    @Autowired
    @Qualifier("VirtualRouterVipBackend")
    protected VirtualRouterVipBackend vipExt;

    @Override
    public void run(final FlowTrigger chain, Map data) {
        final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString());
        if (vr.getGuestL3Networks() == null || vr.getGuestL3Networks().isEmpty()) {
            chain.next();
            return;
        }
        List<VipPeerL3NetworkRefVO> refs = Q.New(VipPeerL3NetworkRefVO.class)
                .in(VipPeerL3NetworkRefVO_.l3NetworkUuid, vr.getGuestL3Networks())
                .list();
        if (refs == null || refs.isEmpty()) {
            chain.next();
            return;
        }

        List<String> vipUuids = new ArrayList<>(refs.stream()
                .map(ref -> ref.getVipUuid())
                .collect(Collectors.toSet()));
        List<VipVO> vips = vipUuids.stream()
                .map(uuid -> (VipVO)Q.New(VipVO.class).eq(VipVO_.uuid, uuid).find())
                .collect(Collectors.toList());
        List<VipInventory> invs = VipInventory.valueOf(vips);
        vipExt.createVipOnVirtualRouterVm(vr, invs, new Completion(chain) {
            @Override
            public void success() {
                List<VirtualRouterVipVO> vrvips = new ArrayList<>();
                for (VipVO vip : vips) {
                    VirtualRouterVipVO vo = dbf.findByUuid(vip.getUuid(), VirtualRouterVipVO.class);
                    if (vo == null) {
                        vo = new VirtualRouterVipVO();
                        vo.setUuid(vip.getUuid());
                        vo.setVirtualRouterVmUuid(vr.getUuid());
                        vrvips.add(vo);
                    }
                }

                if (!vrvips.isEmpty()) {
                    dbf.persistCollection(vrvips);
                }

                chain.next();
            }

            @Override
            public void fail(ErrorCode errorCode) {
                chain.fail(errorCode);
            }
        });
    }

    @Override
    public void rollback(FlowRollback chain, Map data) {
        chain.rollback();
    }
}

@@ -900,87 +900,9 @@
 til.
-ArrayList;%0Aimport java.util.Arrays;%0Aimport java.util.List;%0Aimport java.util.Map
+*
 ;%0Aim
@@ -1402,24 +1402,249 @@
 toString());
+%0A%0A        List%3CString%3E vrVips = Q.New(VirtualRouterVipVO.class).eq(VirtualRouterVipVO_.virtualRouterVmUuid, vr.getUuid())%0A                .select(VirtualRouterVipVO_.uuid).listValues();%0A        List%3CString%3E peerL3Vips = null;
 %0A        if 
@@ -1668,27 +1668,28 @@
 works() 
-=
+!
 = null 
-%7C%7C 
+&& !
 vr.getGu
@@ -1733,65 +1733,27 @@
     
-chain.next();%0A            return;%0A        %7D%0A        List%3C
+peerL3Vips = Q.New(
 VipP
@@ -1773,22 +1773,22 @@
 efVO
-%3E refs = Q.New
+.class).select
 (Vip
@@ -1805,22 +1805,25 @@
 orkRefVO
-.class
+_.vipUuid
 )%0A      
@@ -1832,16 +1832,20 @@
         
+    
 .in(VipP
@@ -1919,21 +1919,31 @@
         
+    
 .list
+Values
 ();%0A    
@@ -1950,31 +1950,84 @@
     
-if (refs =
+%7D%0A%0A        Set%3CString%3E vipUuids = null;%0A        if (vrVips !
 = null 
-%7C%7C ref
+&& !vrVip
 s.is
@@ -2049,35 +2049,55 @@
         
-chain.next(
+vipUuids = new HashSet%3C%3E(vrVips
 );%0A     
        r
@@ -2092,141 +2092,249 @@
     
+   %7D%0A%0A
        
-return;%0A  
+ if (peerL3Vips != null && !peerL3Vips.isEmpty()) %7B%0A
      
- %7D%0A%0A
        
- List%3CString%3E vipUuids = new ArrayList%3C%3E(refs.stream()%0A                .map(ref -%3E ref.getVipUuid(
+if (vipUuids == null) %7B%0A                vipUuids = new HashSet%3C%3E(peerL3Vips);%0A            %7D else %7B%0A                vipUuids.addAll(new HashSet%3CString%3E(peerL3Vips
 ))
+;
 %0A   
@@ -2346,42 +2346,109 @@
     
+%7D%0A
     
-.collect(Collectors.toSet()));
+    %7D%0A%0A        if (vipUuids == null) %7B%0A            chain.next();%0A            return;%0A        %7D%0A
 %0A   

install vpc router public interface ip as vip to vyos