#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
BannedFuncDetector - Banned Functions Module

This module provides the definitive catalog of banned/insecure functions
according to Microsoft and other security guidelines. Functions are organized
by category for better analysis and reporting.

The banned functions list includes dangerous string manipulation, memory operations,
file I/O, process control, and other APIs known to cause security vulnerabilities
when used improperly.

Author: Marc Rivero | @seifreed
"""

from typing import Any

from bannedfuncdetector.domain.entities import CATEGORY_RISK_WEIGHTS

# =============================================================================
# BANNED FUNCTIONS - CATEGORIZED
# =============================================================================
# Complete list of functions banned by Microsoft and other security guidelines,
# organized by category for better analysis and reporting.

BANNED_FUNCTIONS_CATEGORIZED: dict[str, list[str]] = {
    # Banned string copy functions
    "string_copy": [
        "strcpy", "strcpyA", "strcpyW", "wcscpy", "_tcscpy", "_mbscpy",
        "StrCpy", "StrCpyA", "StrCpyW", "lstrcpy", "lstrcpyA", "lstrcpyW",
        "_tccpy", "_mbccpy", "_ftcscpy", "strncpy", "wcsncpy", "_tcsncpy",
        "_mbsncpy", "_mbsnbcpy", "StrCpyN", "StrCpyNA", "StrCpyNW", "StrNCpy",
        "strcpynA", "StrNCpyA", "StrNCpyW", "lstrcpyn", "lstrcpynA", "lstrcpynW",
    ],

    # Banned string concatenation functions
    "string_concat": [
        "strcat", "strcatA", "strcatW", "wcscat", "_tcscat", "_mbscat",
        "StrCat", "StrCatA", "StrCatW", "lstrcat", "lstrcatA", "lstrcatW",
        "StrCatBuff", "StrCatBuffA", "StrCatBuffW", "StrCatChainW", "_tccat",
        "_mbccat", "_ftcscat", "strncat", "wcsncat", "_tcsncat", "_mbsncat",
        "_mbsnbcat", "StrCatN", "StrCatNA", "StrCatNW", "StrNCat", "StrNCatA",
        "StrNCatW", "lstrncat", "lstrcatnA", "lstrcatnW", "lstrcatn",
    ],

    # Banned string format functions (sprintf family)
    "string_format": [
        "sprintfW", "sprintfA", "wsprintf", "wsprintfW", "wsprintfA", "sprintf",
        "swprintf", "_stprintf", "wvsprintf", "wvsprintfA", "wvsprintfW",
        "vsprintf", "_vstprintf", "vswprintf", "_snwprintf", "_snprintf",
        "_sntprintf", "nsprintf",
    ],

    # Banned string input functions
    "string_input": [
        "gets", "_getts", "_gettws",
    ],

    # Banned string token functions
    "string_token": [
        "strtok", "_tcstok", "wcstok", "_mbstok",
    ],

    # Banned string search/comparison functions
    "string_search": [
        "strlen", "strchr", "strrchr", "strspn", "strcspn", "strpbrk",
        "strstr", "stricmp", "strcasecmp",
    ],

    # Banned makepath/splitpath functions
    "path_manipulation": [
        "makepath", "_tmakepath", "_makepath", "_wmakepath",
        "splitpath", "_tsplitpath", "_splitpath", "_wsplitpath",
    ],

    # Banned scanf functions
    "scanf": [
        "scanf", "wscanf", "_tscanf", "sscanf", "swscanf", "_stscanf",
        "fscanf", "vscanf", "vfscanf", "vsscanf",
    ],

    # Banned itoa functions
    "number_conversion": [
        "itoa", "_itoa", "_itow", "_i64toa", "_i64tow", "_ui64toa",
        "_ui64tot", "_ui64tow", "_ultoa", "_ultot", "_ultow",
    ],

    # Banned memory manipulation functions
    "memory": [
        "memcpy", "RtlCopyMemory", "CopyMemory", "wmemcpy", "memccpy",
        "memmove", "RtlMoveMemory", "MoveMemory", "wmemmove",
        "memset", "RtlFillMemory", "FillMemory", "wmemset",
        "memcmp", "RtlCompareMemory", "CompareMemory", "wmemcmp",
        "memchr", "wmemchr", "malloc", "calloc", "realloc", "free",
        "alloca", "WriteProcessMemory",
    ],

    # Banned file manipulation functions
    "file": [
        "fopen", "_wfopen", "fclose", "fread", "fwrite", "fprintf",
        "fgets", "fputs", "fseek", "ftell", "rewind", "fflush", "ferror",
        "feof", "clearerr", "tmpfile", "tmpnam", "freopen", "_wfreopen",
        "fgetpos", "fsetpos", "ungetc", "setvbuf", "setbuf", "perror",
        "remove", "rename", "_wrename", "fputc", "fgetc", "putc", "getc",
        "getchar", "open", "close", "read", "write", "lseek",
        "unlink",
    ],

    # Banned directory manipulation functions
    "directory": [
        "opendir", "readdir", "closedir", "rewinddir", "scandir", "seekdir",
        "telldir", "mkdir", "rmdir",
    ],

    # Banned process manipulation functions
    "process": [
        "system", "popen", "pclose", "execl", "execle", "execlp", "execv",
        "execve", "execvp", "execvpe", "_execl", "_execle", "_execlp",
        "_execlpe", "_execv", "_execve", "_execvp", "_execvpe", "spawn",
        "_spawn", "_spawnl", "_spawnle", "_spawnlp", "_spawnlpe", "_spawnv",
        "_spawnve", "_spawnvp", "_spawnvpe", "fork", "vfork", "wait", "waitpid",
        "exec",
    ],

    # Banned signal manipulation functions
    "signal": [
        "signal", "raise", "kill", "sigaction", "sigemptyset", "sigfillset",
        "sigaddset", "sigdelset", "sigismember", "sigpending", "sigprocmask",
        "sigsuspend", "sigwait",
    ],

    # Banned time manipulation functions
    "time": [
        "time", "ctime", "asctime", "gmtime", "localtime", "mktime",
        "strftime", "strptime", "clock", "difftime", "sleep", "usleep",
        "nanosleep", "gettimeofday", "poll",
    ],

    # Banned environment manipulation functions
    "environment": [
        "getenv", "setenv", "putenv", "unsetenv", "clearenv", "_wgetenv",
        "_wputenv", "_wsetenv",
    ],

    # Banned user manipulation functions
    "user": [
        "getlogin", "getpwnam", "getpwuid", "getgrnam", "getgrgid", "getspnam",
        "getspent", "setpwent", "endpwent", "setgrent", "endgrent", "setspent",
        "endspent", "getpwent",
    ],

    # Banned network manipulation functions
    "network": [
        "socket", "connect", "bind", "listen", "accept", "send", "recv",
        "sendto", "recvfrom", "gethostbyname", "gethostbyaddr", "getservbyname",
        "getservbyport", "getaddrinfo", "freeaddrinfo", "getnameinfo",
        "inet_ntoa", "inet_addr", "inet_aton", "inet_ntop", "inet_pton",
        "setsockopt", "getsockname", "getpeername",
    ],

    # Banned thread manipulation functions
    "thread": [
        "pthread_create", "pthread_join", "pthread_detach", "pthread_cancel",
        "pthread_exit", "pthread_attr_init", "pthread_attr_destroy",
        "pthread_attr_setdetachstate", "pthread_attr_getdetachstate",
        "pthread_attr_setschedpolicy", "pthread_attr_getschedpolicy",
        "pthread_attr_setschedparam", "pthread_attr_getschedparam",
        "pthread_attr_setstacksize", "pthread_attr_getstacksize",
        "pthread_attr_setstackaddr", "pthread_attr_getstackaddr",
        "pthread_attr_setstack", "pthread_attr_getstack",
        "pthread_attr_setguardsize", "pthread_attr_getguardsize",
        "pthread_attr_setscope", "pthread_attr_getscope",
        "pthread_mutex_init", "pthread_mutex_destroy", "pthread_mutex_lock",
        "pthread_mutex_trylock", "pthread_mutex_unlock", "pthread_mutex_timedlock",
        "pthread_mutexattr_init", "pthread_mutexattr_destroy",
        "pthread_mutexattr_setpshared", "pthread_mutexattr_getpshared",
        "pthread_mutexattr_settype", "pthread_mutexattr_gettype",
        "pthread_mutexattr_setprotocol", "pthread_mutexattr_getprotocol",
        "pthread_mutexattr_setprioceiling", "pthread_mutexattr_getprioceiling",
        "pthread_cond_init", "pthread_cond_destroy", "pthread_cond_wait",
        "pthread_cond_timedwait", "pthread_cond_signal", "pthread_cond_broadcast",
        "pthread_condattr_init", "pthread_condattr_destroy",
        "pthread_condattr_setpshared", "pthread_condattr_getpshared",
        "pthread_condattr_setclock", "pthread_condattr_getclock",
        "pthread_rwlock_init", "pthread_rwlock_destroy", "pthread_rwlock_rdlock",
        "pthread_rwlock_tryrdlock", "pthread_rwlock_timedrdlock",
        "pthread_rwlock_wrlock", "pthread_rwlock_trywrlock",
        "pthread_rwlock_timedwrlock", "pthread_rwlock_unlock",
        "pthread_rwlockattr_init", "pthread_rwlockattr_destroy",
        "pthread_rwlockattr_setpshared", "pthread_rwlockattr_getpshared",
        "pthread_spin_init", "pthread_spin_destroy", "pthread_spin_lock",
        "pthread_spin_trylock", "pthread_spin_unlock", "pthread_barrier_init",
        "pthread_barrier_destroy", "pthread_barrier_wait",
        "pthread_barrierattr_init", "pthread_barrierattr_destroy",
        "pthread_barrierattr_setpshared", "pthread_barrierattr_getpshared",
        "pthread_key_create", "pthread_key_delete", "pthread_setspecific",
        "pthread_getspecific", "pthread_once",
    ],

    # Standard I/O functions
    "stdio": [
        "printf", "putchar", "puts", "vprintf", "vfprintf",
    ],
}

# For compatibility, maintain a flat set of all banned functions
BANNED_FUNCTIONS: set[str] = {
    func for funcs in BANNED_FUNCTIONS_CATEGORIZED.values() for func in funcs
}


def _build_lowercase_category_index() -> dict[str, str]:
    """Build a lowercase function name -> category lookup for case-insensitive matching.

    If a function appears in multiple categories, the one with the higher
    risk weight (from entities.CATEGORY_RISK_WEIGHTS) wins.
    """
    index: dict[str, str] = {}
    for category, funcs in BANNED_FUNCTIONS_CATEGORIZED.items():
        cat_weight = CATEGORY_RISK_WEIGHTS.get(category, 5)
        for func in funcs:
            key = func.lower()
            if key in index:
                existing_weight = CATEGORY_RISK_WEIGHTS.get(index[key], 5)
                if cat_weight <= existing_weight:
                    continue  # keep the higher-risk category
            index[key] = category
    return index


_CATEGORY_INDEX: dict[str, str] = _build_lowercase_category_index()


def get_category_for_function(func_name: str) -> str | None:
    """
    Get the category for a given banned function name (case-insensitive).

    Args:
        func_name: The name of the function to look up.

    Returns:
        The category name if found, None otherwise.

    Examples:
        >>> get_category_for_function("strcpy")
        'string_copy'
        >>> get_category_for_function("STRCPY")
        'string_copy'
        >>> get_category_for_function("malloc")
        'memory'
        >>> get_category_for_function("unknown_func")
        None
    """
    return _CATEGORY_INDEX.get(func_name.lower())


def get_highest_risk_category(func_names: list[str] | tuple[str, ...]) -> str | None:
    """Return the category with the highest risk weight among the given functions.

    Args:
        func_names: Banned function names to evaluate.

    Returns:
        The category with the highest CATEGORY_RISK_WEIGHTS, or None if none found.

    Examples:
        >>> get_highest_risk_category(["printf", "strcpy"])
        'string_copy'
        >>> get_highest_risk_category(["printf"])
        'stdio'
    """
    best_category: str | None = None
    best_weight = -1
    for name in func_names:
        cat = get_category_for_function(name)
        if cat is not None:
            weight = CATEGORY_RISK_WEIGHTS.get(cat, 5)
            if weight > best_weight:
                best_weight = weight
                best_category = cat
    return best_category


def get_banned_functions_set(config: Any = None) -> set[str]:
    """
    Get the set of banned functions from config or defaults.

    This is the canonical implementation used throughout the codebase
    for obtaining the set of banned function names.

    Args:
        config: Configuration repository instance. If None, uses BANNED_FUNCTIONS.
            If config has a 'banned_functions' key, those will be used instead.

    Returns:
        A set of banned function names.

    Examples:
        >>> banned = get_banned_functions_set()
        >>> "strcpy" in banned
        True
        >>> "malloc" in banned
        True
    """
    if config is None:
        return BANNED_FUNCTIONS

    # Config may provide custom banned functions list
    banned_functions_list = config.get("banned_functions") if hasattr(config, 'get') else None
    if banned_functions_list:
        return set(banned_functions_list)

    return BANNED_FUNCTIONS
