import platform
machineArch = platform.machine()

import re
import whatap.util.process_util as process_util
import psutil
import time

cpuinfo = process_util.executeCmd('kstat -m cpu_info')
cputype = None
for l in cpuinfo.split('\n'):
    if l and l.startswith('cpu_type'):
        cputype = ' '.join(l.split()[1:])
        break

cpu_core = psutil.cpu_count()

totalsize = psutil.virtual_memory().total


system_info = {}

def GetCPUNum():
    return cpu_core

def GetCPUType():
    return cputype

def GetMemorySize():
    return totalsize

def GetMachineArch():
    return machineArch

def GetOSRelease():
    return " ".join([platform.system(), platform.release()])

serverInfoV2 = None
_boot_epoch_ts = None


def _has_cmd(cmd):
    try:
        out = process_util.executeCommandShellWithTimeout(
            'command -v %s >/dev/null 2>&1 && echo yes' % cmd, timeout=3)
        return out == 'yes'
    except Exception:
        return False


def _is_ldm_control():
    try:
        out = process_util.executeCommandShellWithTimeout(
            'command -v ldm >/dev/null 2>&1 && ldm list >/dev/null 2>&1 && echo yes', timeout=10)
        return out == 'yes'
    except Exception:
        return False


def _parse_virtinfo_ap_role(out):
    if not out:
        return ''
    for line in out.split('\n'):
        if not line.startswith('DOMAINROLE|'):
            continue
        impl = None
        control = None
        for part in line.split('|')[1:]:
            if part.startswith('impl='):
                impl = part[len('impl='):]
            elif part.startswith('control='):
                control = part[len('control='):]
        if impl == 'LDoms':
            if control == 'true':
                return 'LDOM_CONTROL'
            if control == 'false':
                return 'LDOM_GUEST'
            return 'LDOM_UNKNOWN'
    return ''


def _has_token_current(out, first):
    if not out:
        return False
    for line in out.split('\n'):
        tokens = line.split()
        if len(tokens) >= 2 and tokens[0] == first and tokens[1] == 'current':
            return True
    return False


def _parse_virtinfo_control_role(out):
    if not out:
        return ''
    for line in out.split('\n'):
        if re.search(r'control-role\s+true', line):
            return 'LDOM_CONTROL'
        if re.search(r'control-role\s+false', line):
            return 'LDOM_GUEST'
        if re.search(r'\|control=true(\||$)', line):
            return 'LDOM_CONTROL'
        if re.search(r'\|control=false(\||$)', line):
            return 'LDOM_GUEST'
    return ''


def _has_any_virtual_hint(zname, vap, vlist, vget, ldm_cached):
    if zname and zname != 'global':
        return True
    for text, marker in (
        (vap, 'DOMAINROLE|'),
        (vap, 'impl=LDoms'),
        (vap, 'Virtual machines (LDoms)'),
        (vlist, 'logical-domain'),
        (vlist, 'kernel-zone'),
        (vget, 'logical-domain'),
        (vget, 'kernel-zone'),
    ):
        if text and marker in text:
            return True
    return ldm_cached


def _classify_server():
    zname = process_util.executeCommandShellWithTimeout('zonename 2>/dev/null', timeout=5).strip()
    if zname and zname != 'global':
        return 'Virtual', 'non-global zone'

    has_virtinfo = _has_cmd('virtinfo')
    vap = ''
    vget = ''
    vlist = ''
    if has_virtinfo:
        vap = process_util.executeCommandShellWithTimeout('virtinfo -ap 2>/dev/null', timeout=10)
        role = _parse_virtinfo_ap_role(vap)
        if role == 'LDOM_CONTROL':
            return 'Virtual', 'LDOM control domain'
        if role == 'LDOM_GUEST':
            return 'Virtual', 'LDOM guest domain'

        vget = process_util.executeCommandShellWithTimeout('virtinfo -c current get all 2>/dev/null', timeout=10)
        if not vget:
            vget = process_util.executeCommandShellWithTimeout('virtinfo get all 2>/dev/null', timeout=10)
        vlist = process_util.executeCommandShellWithTimeout('virtinfo 2>/dev/null', timeout=10)

        if _has_token_current(vget, 'kernel-zone') or _has_token_current(vlist, 'kernel-zone'):
            return 'Virtual', 'kernel zone'

        ldm_cache = []
        def _is_ctrl():
            if not ldm_cache:
                ldm_cache.append(_is_ldm_control())
            return ldm_cache[0]

        if _has_token_current(vget, 'logical-domain'):
            role = _parse_virtinfo_control_role(vget)
            if role == 'LDOM_CONTROL':
                return 'Virtual', 'LDOM control domain'
            if role == 'LDOM_GUEST':
                return 'Virtual', 'LDOM guest domain'
            return ('Virtual', 'LDOM control domain') if _is_ctrl() else ('Virtual', 'LDOM guest domain')

        if _has_token_current(vlist, 'logical-domain'):
            return ('Virtual', 'LDOM control domain') if _is_ctrl() else ('Virtual', 'LDOM guest domain')

    ldm_ctrl = _is_ldm_control()
    if ldm_ctrl:
        return 'Virtual', 'LDOM control domain'

    if vap and 'Virtual machines (LDoms) are supported but not enabled' in vap:
        return 'Virtual', 'Unknown'

    if _has_any_virtual_hint(zname, vap, vlist, vget, ldm_ctrl):
        return 'Virtual', 'Unknown'

    return 'Physical', 'Bare metal/global zone'


def initServerV2():
    global serverInfoV2
    global _boot_epoch_ts

    bootEpoch = process_util.executeCommandShellWithTimeout(''' uptime | perl -ne \'/.*up (\d+) day\(s\), +(\d+):(\d+),.*/; $total=((($1*24+$2)*60+$3)*60); $now=time(); $now-=$total; print $now,"\n";\' ''')
    _boot_epoch_ts = float(bootEpoch)
    bootTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(_boot_epoch_ts))

    serverInfoV2 = {
        "hostname":process_util.executeCommandShellWithTimeout('''hostname'''),
        "model":process_util.executeCommandShellWithTimeout('''echo `prtconf -b |grep banner-name |cut -f2 -d:`'''),
        "hwSerial":process_util.executeCommandShellWithTimeout("""prtdiag -v | awk '/Chassis Serial/{getline; getline; print}'"""),
        "OSVersion":process_util.executeCommandShellWithTimeout('''echo `uname -o` `uname -v` `uname -p` \(`uname -s` `uname -r`\)'''),
        "OSType":process_util.executeCommandShellWithTimeout('''uname -s'''),
        "firmware":process_util.executeCommandShellWithTimeout("""prtdiag -v | awk '/FW Version/{getline; getline; getline; print }'"""),
        "nCores":process_util.executeCommandShellWithTimeout("""kstat -m cpu_info |grep core_id | awk '{ print $2 }' | sort -u | wc -l | tr -d ' '"""),
        "lCores":process_util.executeCommandShellWithTimeout("""kstat -m cpu_info |grep core_id | awk '{ print $2 }' | wc -l | tr -d ' '"""),
        "frequency":process_util.executeCommandShellWithTimeout("""kstat -m cpu_info | grep clock_MHz | head -1 | awk '{print $2}'"""),
        "cpuType": process_util.executeCommandShellWithTimeout("""prtdiag | awk '/Implementation/{getline; getline; print $4}'"""),
        "memTotal":  process_util.executeCommandShellWithTimeout("""prtconf | grep "^Memory size:" | awk '{print $3}'"""),
        "IP_all":  process_util.executeCommandShellWithTimeout("""ifconfig -a | grep -w inet | egrep -v "127.0.0.1|0.0.0.0" | awk '{print $2}' | cut -d'/' -f 1"""),
        "timezone":  process_util.executeCommandShellWithTimeout("""cat /etc/default/init | grep ^TZ | awk -F= '{print $2}'"""),    
        "bootTime": bootTime,
    }
    server_type, server_type_detail = _classify_server()
    serverInfoV2['serverType'] = server_type
    serverInfoV2['serverTypeDetail'] = server_type_detail
    serverInfoV2['systemArchitecture'] = platform.machine()

def GetServerInfoV2():
    global serverInfoV2
    if serverInfoV2 == None:
        initServerV2()

    if _boot_epoch_ts is not None:
        serverInfoV2['uptime'] = int((time.time() - _boot_epoch_ts) / 86400)

    return serverInfoV2



def GetNtpInfo():
    from whatap.osinfo.ntp_common import build_ntp_info
    import whatap.util.process_util as process_util
    daemon = ""
    in_use = False
    try:
        svc_out = process_util.executeCommandShellWithTimeout('svcs svc:/network/ntp 2>/dev/null | grep online | head -1', timeout=5).strip()
        if svc_out:
            daemon = 'ntpd'
            in_use = True
        else:
            ps_out = process_util.executeCommandShellWithTimeout('ps -ef 2>/dev/null | grep ntpd | grep -v grep | head -1', timeout=5).strip()
            if ps_out:
                daemon = 'ntpd'
                in_use = True
    except Exception:
        pass
    return build_ntp_info(daemon, in_use)
