from copy import deepcopy
import random
from TDhelper.network.http.REST_HTTP import GET
class HostManager:
    def __init__(self) -> None:
        self.__host_cnf_backup__={}
        self.__host_cnf__ = {}
        self.__host__=[]
        self.__host_len__ = 0
        #self.__health_sniffer__ = ""

    def __backup_host__(self):
        self.__host_cnf_backup__= deepcopy(self.__host_cnf__)
        
    def get_per_http_host(self):
        try:
            return self.__generateHost__(self.getHost())
        except Exception as e:
            raise e

    def getHost(self):
        """getHost
            get an access host cnf.
        Parameters:
            self - <class: HostManager>, hostManager instance.
        Returns:
            success - <class, json>, host cnf json.
            fail - None.
        Raises:
            None
        """
        v = 0 if self.__host_len__ == 1 else random.randint(0, self.__host_len__-1)
        result= self.__host_cnf__[self.__host__[v]]
        result["serverId"]= self.__host__[v]
        if result['status']:
            return result
        else:
            return None

    def get_host_by_key(self,key):
        return self.__host_cnf__[key]

    def register(self, serverId, host, port:int=80,sniffer="/api/sniffer", proto:str="http://", status=True):
        """register
            register an rpc host
        Parameters:
            self - <class: HostManager>, hostManager instance.
            serverId - <class: int>, serverId
            host - <class: str>, ip or domain
            port - <class: int>, port. default 80
            sniffer - <class: str>, the healthy sniffer uri. default /api/sniffer
            proto - <class: str>, http:// or https://. default http://
            status - <class: bool>, default True
        Returns:
            None
        Raises:
            10000 - key already exists.
        """
        serverId= str(serverId)
        proto=self.__checken_proto__(proto)
        if serverId not in self.__host_cnf__:
            self.__host_cnf__[serverId]={
                "proto":proto,
                "host":host,
                "port":port,
                "status":status,
                "sniffer":sniffer
            }
            if serverId not in self.__host_cnf_backup__:
                self.__host_cnf_backup__={
                    "proto":proto,
                    "host":host,
                    "port":port,
                    "status":status,
                    "sniffer":sniffer
                }
            self.__host__.append(serverId)
            self.__host_len__= len(self.__host__)
        else:
            raise (Exception("10000, '%s' already exists."%serverId))

    def __checken_proto__(self,v):
        v=v.replace(":","")
        v=v.replace("/","")
        v=v+"://"
        return v

    def reload(self):
        '''reload
            reload host conf by host conf backup.
        '''
        self.__host_cnf__ = {}
        self.__host__=[]
        self.__host_len__ = 0
        #self.__health_sniffer__ = ""
        for k,v in self.__host_cnf_backup__.items():
            self.register(k,v["host"],v["port"],v["sniffer"],v["proto"],v["status"])
    
    def delete(self, serverId):
        """delete
            delete a host cnf.
        Parameters:
            self - <class, HostManager>, hostmanager instance.
            serverId - <class, int|str>, serverId.
        Returns:
            success - serverId
            fail - None
        Raises:
            None.
        """
        if str(serverId) in self.__host_cnf__:
            m_result= self.__host_cnf__.pop(serverId)
            self.__host__.remove(serverId)
            self.__host_len__= len(self.__host__)
            return m_result
        else:
            return None
    
    def health(self):
        """health
            check host health status.
        Parameters:
            self - <class, HostManager>, hostmanager instance.
        Returns:
            <class, json>, cheked result.
            json desc
                statistics - <class, json>, checked result.
                    total - host count.
                    health - checked it's success count.
                    unhealthy - checked it's fail count.
                health - <class, list>, health serverId list.
                unhealthy - <class, list>, unhealthy serverId list.
        Raises:
            None.
        """
        result={
            "statistics":{
                "total":self.__host_len__,
                "health":0,
                "unhealthy":0,
            },
            "health":[],
            "unhealthy":[]
        }
        for k in self.__host__:
            m_uri= self.__generateHost__(self.__host_cnf__[k])
            if m_uri:
                m_uri+= "/"+self.__host_cnf__[k]["sniffer"].strip('/').replace('\\',"/")
                status, body =GET(m_uri,time_out=5)
                if status==200:
                    result["health"].append(k)
                else:
                    result["unhealthy"].append(k)
            else:
                result['unhealthy'].append(k)
        for k in result["unhealthy"]:    
            self.delete(k)
        result["statistics"]["health"]=len(result["health"])
        result["statistics"]["unhealthy"]=len(result["unhealthy"])
        return result

    def __generateHost__(self,uri_cnf:dict):
        proto= uri_cnf["proto"]
        host= uri_cnf["host"]
        port= str(uri_cnf["port"])
        if uri_cnf["status"]:
            if port!=80 or port!="80":
                return proto+host+":"+port
            else:
                return proto+host
        else:
            return None