import re
import whatap.agent.conf.configure as conf

_PROCGROUP_PREFIX = 'procgroup_'

_rule_cache_signature = None
_compiled_rules = None

_pid_result_cache = {}


def _build_rules(config_dict):
    rules = []
    for key, value in config_dict.items():
        if not key.startswith(_PROCGROUP_PREFIX):
            continue
        group_id = key[len(_PROCGROUP_PREFIX):]
        if not group_id:
            continue
        parts = value.split('@@', 3) if value else []
        group_name = parts[0].strip() if len(parts) > 0 else ''
        if not group_name:
            continue
        user_pat = parts[1].strip() if len(parts) > 1 else ''
        cmd2_pat = parts[2].strip() if len(parts) > 2 else ''
        except_pat = parts[3].strip() if len(parts) > 3 else ''
        try:
            user_re = re.compile(user_pat) if user_pat else None
            cmd2_re = re.compile(cmd2_pat) if cmd2_pat else None
            except_re = re.compile(except_pat) if except_pat else None
        except re.error:
            continue
        rules.append((group_name, user_re, cmd2_re, except_re))
    return rules


def _get_rules():
    global _rule_cache_signature, _compiled_rules
    config_dict = conf.GetConfig().searchKey(_PROCGROUP_PREFIX)
    current_signature = tuple(sorted(config_dict.items()))
    if current_signature != _rule_cache_signature:
        _rule_cache_signature = current_signature
        _compiled_rules = _build_rules(config_dict)
        _pid_result_cache.clear()
    return _compiled_rules


def find_custom_group(pid, user, cmd2):
    rules = _get_rules()
    if not rules:
        return None

    cache_key = (pid, user or '', cmd2 or '')
    if cache_key in _pid_result_cache:
        return _pid_result_cache[cache_key]

    result = None
    u = user or ''
    c = cmd2 or ''
    for group_name, user_re, cmd2_re, except_re in rules:
        if user_re and not user_re.search(u):
            continue
        if cmd2_re and not cmd2_re.search(c):
            continue
        if except_re and except_re.search(c):
            continue
        result = group_name
        break

    _pid_result_cache[cache_key] = result
    return result


def gc_pid_cache(live_pids):
    dead = [k for k in _pid_result_cache if k[0] not in live_pids]
    for k in dead:
        del _pid_result_cache[k]
