import whatap.pack.tagcount_pack as tagcount_pack
import whatap.osinfo as osinfo
import whatap.agent.secure.security_master as secure
import whatap.agent.conf.configure as config
from whatap.util.hash_util import HashUtil as hashutil
from whatap.value.list_value import ListValue
from whatap.osinfo.os_parameter_common import parse_custom_params


class TaskInfraOsParameter:
    OS_PARAMETER = "infra_os_parameter{h1}"

    # OS parameter collection is asynchronous (BackgroundCollector): the
    # first GetOsParameterList() call only starts the background thread and
    # returns an empty list, so the first tick sends nothing. Without
    # priming the next chance comes a full interval (default 3600s) later
    # (SERVER-1944). Until the first pack is actually built, interval()
    # returns PRIME_INTERVAL so CounterManager retries quickly, then falls
    # back to the configured interval.
    # PRIME_INTERVAL must be >= 5: CounterManager skips pack-list tasks
    # whose interval() is less than 5.
    PRIME_INTERVAL = 5
    # Stop priming after this many empty attempts so hosts without any
    # tunable commands do not keep polling every PRIME_INTERVAL forever.
    PRIME_MAX_ATTEMPTS = 12

    def __init__(self, interval=3600):
        self.intervalValue = interval
        self.recType = 2
        # No priming needed when the configured interval is already fast.
        self.primed = interval <= TaskInfraOsParameter.PRIME_INTERVAL
        self.primeAttempts = 0

    def interval(self):
        if not self.primed:
            return TaskInfraOsParameter.PRIME_INTERVAL
        return self.intervalValue

    def _custom_params(self):
        try:
            raw = config.GetConfig().getProperty("InfraOsParameterCustom", "")
        except Exception:
            raw = ""
        return parse_custom_params(raw)

    def process(self, os_, pcode, oid, now):
        if not self.primed:
            # Count the attempt up front so repeated failures (empty cache
            # or exceptions) still hit the cap and end the fast polling.
            self.primeAttempts += 1
            if self.primeAttempts >= TaskInfraOsParameter.PRIME_MAX_ATTEMPTS:
                self.primed = True

        params = osinfo.GetOsParameterList(self._custom_params())
        if not params:
            return None

        self.primed = True

        secu = secure.GetSecurityMaster()
        p = tagcount_pack.TagCountPack()
        p.pcode = pcode
        p.oid = oid
        p.time = now
        p.category = TaskInfraOsParameter.OS_PARAMETER
        p.putTag("oname", str(secu.oname))
        p.putTag("!rectype", str(self.recType))

        idList = ListValue()
        parameterList = ListValue()
        categoryList = ListValue()
        osList = ListValue()
        valueList = ListValue()
        customList = ListValue()

        for item in params:
            # @id is the (parameter + category) combination (SERVER-1794 spec)
            key = hashutil.hashFromString("{}{}".format(item.parameter, item.category))
            idList.addLong(key)
            parameterList.addString(item.parameter if item.parameter else "")
            categoryList.addString(item.category if item.category else "")
            osList.addString(item.os if item.os else "")
            valueList.addString(str(item.value) if item.value is not None else "")
            customList.addBoolean(bool(item.custom))

        p.put("@id", idList)
        p.put("parameter", parameterList)
        p.put("category", categoryList)
        p.put("os", osList)
        p.put("value", valueList)
        p.put("custom", customList)

        return [p]
