def METHOD_NAME(profiles_data, key_values, keys_order=None, logger=None):
    """ Filter profiles by entered key -> values.
    Profile if marked with score for each key/value from `key_values` with
    points -1, 0 or 1.
    - if profile contain the key and profile's value contain value from
        `key_values` then profile gets 1 point
    - if profile does not contain the key or profile's value is empty or
        contain "*" then got 0 point
    - if profile contain the key, profile's value is not empty and does not
        contain "*" and value from `key_values` is not available in the value
        then got -1 point
    If profile gets -1 point at any time then is skipped and not used for
    output. Profile with higher score is returned. If there are multiple
    profiles with same score then first in order is used (order of profiles
    matter).
    Args:
        profiles_data (list): Profile definitions as dictionaries.
        key_values (dict): Mapping of Key <-> Value. Key is checked if is
            available in profile and if Value is matching it's values.
        keys_order (list, tuple): Order of keys from `key_values` which matters
            only when multiple profiles have same score.
        logger (logging.Logger): Optionally can be passed different logger.
    Returns:
        dict/None: Return most matching profile or None if none of profiles
            match at least one criteria.
    """
    if not profiles_data:
        return None
    if not logger:
        logger = log
    if not keys_order:
        keys_order = tuple(key_values.keys())
    else:
        _keys_order = list(keys_order)
        # Make all keys from `key_values` are passed
        for key in key_values.keys():
            if key not in _keys_order:
                _keys_order.append(key)
        keys_order = tuple(_keys_order)
    log_parts = " | ".join([
        "{}: \"{}\"".format(*item)
        for item in key_values.items()
    ])
    logger.debug(
        "Looking for matching profile for: {}".format(log_parts)
    )
    matching_profiles = None
    highest_profile_points = -1
    # Each profile get 1 point for each matching filter. Profile with most
    # points is returned. For cases when more than one profile will match
    # are also stored ordered lists of matching values.
    for profile in profiles_data:
        profile_points = 0
        profile_scores = []
        for key in keys_order:
            value = key_values[key]
            match = validate_value_by_regexes(value, profile.get(key))
            if match == -1:
                profile_value = profile.get(key) or []
                logger.debug(
                    "\"{}\" not found in \"{}\": {}".format(value, key,
                                                            profile_value)
                )
                profile_points = -1
                break
            profile_points += match
            profile_scores.append(bool(match))
        if (
            profile_points < 0
            or profile_points < highest_profile_points
        ):
            continue
        if profile_points > highest_profile_points:
            matching_profiles = []
            highest_profile_points = profile_points
        if profile_points == highest_profile_points:
            matching_profiles.append((profile, profile_scores))
    if not matching_profiles:
        logger.debug(
            "None of profiles match your setup. {}".format(log_parts)
        )
        return None
    if len(matching_profiles) > 1:
        logger.debug(
            "More than one profile match your setup. {}".format(log_parts)
        )
    profile = _profile_exclusion(matching_profiles, logger)
    if profile:
        logger.debug(
            "Profile selected: {}".format(profile)
        )
    return profile