package com.ctrip.zeus.service.status.impl;

import com.ctrip.zeus.client.LocalClient;
import com.ctrip.zeus.client.StatusClient;
import com.ctrip.zeus.model.entity.*;
import com.ctrip.zeus.nginx.entity.S;
import com.ctrip.zeus.nginx.entity.UpstreamStatus;
import com.ctrip.zeus.service.model.GroupRepository;
import com.ctrip.zeus.service.model.SlbRepository;
import com.ctrip.zeus.service.status.GroupStatusService;
import com.ctrip.zeus.service.status.StatusService;
import com.ctrip.zeus.util.AssertUtils;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * User: mag
 * Date: 4/1/2015
 * Time: 2:26 PM
 */
@Service("groupStatusService")
public class GroupStatusServiceImpl implements GroupStatusService {
    private static DynamicIntProperty nginxStatusPort = DynamicPropertyFactory.getInstance().getIntProperty("slb.nginx.status-port", 10001);
    private static DynamicIntProperty adminServerPort = DynamicPropertyFactory.getInstance().getIntProperty("server.port", 8099);

    @Resource
    SlbRepository slbRepository;

    @Resource
    GroupRepository groupRepository;

    @Resource
    StatusService statusService;

    private long currentSlbId = -1L;

    @Override
    public List<GroupStatus> getAllGroupStatus() throws Exception {
        List<GroupStatus> result = new ArrayList<>();
        List<Slb> slbList = slbRepository.list();
        for (Slb slb : slbList) {
            result.addAll(getAllGroupStatus(slb.getId()));
        }
        return result;
    }

    @Override
    public List<GroupStatus> getAllGroupStatus(Long slbId) throws Exception {
        List<GroupStatus> result = new ArrayList<>();

        List<GroupSlb> groupSlbs = slbRepository.listGroupSlbsBySlb(slbId);
        for (GroupSlb groupSlb : groupSlbs) {
            GroupStatus appStatus = getGroupStatus(groupSlb.getGroupId(), groupSlb.getSlbId());
            result.add(appStatus);
        }
        return result;
    }

    @Override
    public List<GroupStatus> getGroupStatus(Long groupId) throws Exception {
        List<GroupStatus> result = new ArrayList<>();
        List<Slb> slbList = slbRepository.listByGroups(new Long[]{groupId});
        for (Slb slb : slbList) {
            result.add(getGroupStatus(groupId, slb.getId()));
        }
        return result;
    }
    @Override
    public GroupStatus getLocalGroupStatus(Long groupId , Long slbId) throws Exception
    {
        Slb slb = slbRepository.getById(slbId);
        Group group = groupRepository.getById(groupId);
        AssertUtils.assertNotNull(group, "group Id not found!");
        AssertUtils.assertNotNull(slb, "slb Id not found!");

        GroupStatus status = new GroupStatus();
        status.setGroupId(groupId);
        status.setSlbId(slbId);
        status.setGroupName(group.getName());
        status.setSlbName(slb.getName());

        List<GroupServer> groupServerList = groupRepository.listGroupServersByGroup(groupId);
        for (GroupServer groupServer : groupServerList) {
            GroupServerStatus serverStatus = getGroupServerStatus(groupId, slbId, groupServer.getIp(), groupServer.getPort());
            status.addGroupServerStatus(serverStatus);
        }
        return status;
    }
    @Override
    public GroupStatus getGroupStatus(Long groupId, Long slbId) throws Exception {
        Slb slb = slbRepository.getById(slbId);
        AssertUtils.assertNotNull(slb, "slbId not found!");
        AssertUtils.assertNotEquals(0,slb.getSlbServers().size(),"Slb doesn't have any slb server!");
        StatusClient client = StatusClient.getClient("http://"+slb.getSlbServers().get(0).getIp()+":"+adminServerPort.get());
        return client.getGroupStatus(groupId,slbId);
    }

    @Override
    public GroupServerStatus getGroupServerStatus(Long groupId, Long slbId, String ip, Integer port) throws Exception {

        GroupServerStatus groupServerStatus = new GroupServerStatus();
        groupServerStatus.setIp(ip);
        groupServerStatus.setPort(port);


        boolean memberUp = statusService.getGroupServerStatus(slbId, groupId, ip);
        boolean serverUp = statusService.getServerStatus(ip);
        boolean backendUp = getUpstreamStatus(groupId,ip,memberUp,serverUp);

        groupServerStatus.setServer(serverUp);
        groupServerStatus.setMember(memberUp);
        groupServerStatus.setUp(backendUp);

        return groupServerStatus;
    }

    //TODO: should include port to get accurate upstream
    private boolean getUpstreamStatus(Long groupId, String ip , boolean memberUp , boolean serverUp) throws Exception {
        if (!(memberUp&&serverUp))
        {
            return false;
        }
        UpstreamStatus upstreamStatus = LocalClient.getInstance().getUpstreamStatus();
        List<S> servers = upstreamStatus.getServers().getServer();
        String upstreamNameEndWith = "_"+groupRepository.getById(groupId).getName();
        for (S server : servers) {
            if (!server.getUpstream().endsWith(upstreamNameEndWith))
            {
                continue;
            }
            String ipPort = server.getName();
            String[] ipPorts = ipPort.split(":");
            if (ipPorts.length == 2){
                if (ipPorts[0].equals(ip)){
                    return "up".equalsIgnoreCase(server.getStatus());
                }
            }
        }
        //Not found status from nginx , ip is mark down or health check is disable
        // return memberUp&&serverUp ,always be true
        return true;
    }
    private boolean isCurrentSlb(Long slbId) throws Exception {
        if (currentSlbId < 0)
        {
            String ip = com.ctrip.zeus.util.S.getIp();
            Slb slb = slbRepository.getBySlbServer(ip);
            if (slb != null )
            {
                currentSlbId = slb.getId();
            }
        }
        return slbId.equals(currentSlbId);
    }
}

@@ -595,24 +595,81 @@
 rtyFactory;%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A
 import org.s
@@ -703,16 +703,16 @@
 ervice;%0A
-
 %0Aimport 
@@ -1401,16 +1401,99 @@
 d = -1L;
+%0A    private Logger LOGGER = LoggerFactory.getLogger(GroupStatusServiceImpl.class);
 %0A%0A    @O
@@ -3761,16 +3761,17 @@
 quals(0,
+ 
 slb.getS
@@ -3789,16 +3789,17 @@
 .size(),
+ 
 %22Slb doe
@@ -4883,89 +4883,8 @@
 n %7B%0A
-        if (!(memberUp&&serverUp))%0A        %7B%0A            return false;%0A        %7D%0A
     
@@ -5474,22 +5474,30 @@
         
-return
+boolean flag =
  %22up%22.eq
@@ -5528,24 +5528,285 @@
 tStatus());%0A
+                    if (!(memberUp&&serverUp))%0A                    %7B%0A                        LOGGER.error(%22nginx status api return status while memberUp and serverUp are down! ip:%22+ip+%22 groupId:%22+groupId);%0A                    %7D%0A                    return flag;%0A
             
@@ -5958,44 +5958,42 @@
 erUp
- ,always be true%0A        return true
+%0A        return memberUp&&serverUp
 ;%0A  

update healthcheck