from typing import List
from typing import Dict
import re


def is_safelisted(value: str, tags: List[str], safelist: Dict[str, Dict[str, List[str]]], substring: bool = False) -> bool:
    """
    Safelists of data that may come up in analysis that is "known good", and we can ignore in the Assemblyline report.
    This method determines if a given value has any safelisted components
    See README section on Assemblyline System Safelist on how to integrate the safelist found in al_config/system_safelist.yaml
    :param value: The value to be checked if it has been safelisted
    :param tags: The tags which will be used for grabbing specific values from the safelist
    :param safelist: The safelist containing matches and regexs
    :param substring: A flag that indicates if we should check if the value is contained within the match
    :return: A boolean indicating if the value has been safelisted
    """
    if not value or not tags or not safelist:
        return False

    if not any(key in safelist for key in ["match", "regex"]):
        return False

    safelist_matches = safelist.get("match", {})
    safelist_regexes = safelist.get("regex", {})

    for tag in tags:
        if tag in safelist_matches:
            for safelist_match in safelist_matches[tag]:
                if value.lower() == safelist_match.lower():
                    return True
                elif substring and safelist_match.lower() in value.lower():
                    return True

        if tag in safelist_regexes:
            for safelist_regex in safelist_regexes[tag]:
                if re.match(safelist_regex, value, re.IGNORECASE):
                    return True

    return False