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


def parse_ntpq():
    server = ""
    offset_ms = 0.0
    offset_dir = 0
    synced = 0
    try:
        output = process_util.executeCommandShellWithTimeout('ntpq -p 2>/dev/null', timeout=10)
        for line in output.split('\n'):
            line = line.strip()
            if not line or line.startswith('remote') or line.startswith('='):
                continue
            if line[0] not in ('*', 'o'):
                continue
            tokens = line[1:].strip().split()
            if len(tokens) < 9:
                continue
            server = tokens[0]
            try:
                offset_val = float(tokens[8])
                offset_ms = abs(offset_val)
                offset_dir = 1 if offset_val > 0 else (-1 if offset_val < 0 else 0)
                synced = 1
            except (ValueError, IndexError):
                pass
            break
    except Exception as e:
        logging_util.error('parse_ntpq error:', e)
    return server, offset_ms, offset_dir, synced


def parse_chronyc():
    server = ""
    offset_ms = 0.0
    offset_dir = 0
    synced = 0
    try:
        output = process_util.executeCommandShellWithTimeout('chronyc sources 2>/dev/null', timeout=10)
        for line in output.split('\n'):
            line = line.strip()
            if not line:
                continue
            if line[0] not in ('^', '='):
                continue
            marker = line[1] if len(line) > 1 else ''
            if marker not in ('*', 'o'):
                continue
            tokens = line[2:].strip().split()
            if len(tokens) < 7:
                continue
            server = tokens[0]
            try:
                offset_str = tokens[5]
                m = re.search(r'([+-]?\d+(?:\.\d+)?)', offset_str)
                if not m:
                    continue
                val = float(m.group(1))
                sign = -1 if val < 0 else (1 if val > 0 else 0)
                unit_m = re.search(r'[a-zA-Z]+', offset_str)
                unit = unit_m.group(0).lower() if unit_m else 'ms'
                if 'ns' in unit:
                    val = abs(val) / 1e6
                elif 'us' in unit:
                    val = abs(val) / 1e3
                elif unit == 's':
                    val = abs(val) * 1e3
                else:
                    val = abs(val)
                offset_ms = val
                offset_dir = sign
                synced = 1
            except (ValueError, IndexError):
                pass
            break
    except Exception as e:
        logging_util.error('parse_chronyc error:', e)
    return server, offset_ms, offset_dir, synced


def get_timezone():
    try:
        return time.strftime('%Z')
    except Exception:
        return ""


def build_ntp_info(daemon, ntq_in_use):
    info = {
        'checkTime': int(time.time() * 1000),
        'ntpInUse': 1 if ntq_in_use else 0,
        'ntpDaemon': daemon,
        'timeSynced': 0,
        'ntpServer': "",
        'offset': 0.0,
        'offsetDirection': 0,
        'timeZone': get_timezone(),
    }
    if not ntq_in_use:
        return info

    server, offset_ms, offset_dir, synced = "", 0.0, 0, 0

    if daemon == 'chrony':
        server, offset_ms, offset_dir, synced = parse_chronyc()
    else:
        server, offset_ms, offset_dir, synced = parse_ntpq()

    info['ntpServer'] = server
    info['offset'] = offset_ms
    info['offsetDirection'] = offset_dir
    info['timeSynced'] = synced
    return info
