import re


def parse_structure_info(data: bytes) -> dict:
    """
    Parses structure info to a dictionary

    Args:
          data: data (contents) of Structure_Info.txt read in binary mode

    Returns:
          filtered_data: A dictionary with selected fields namely
          - sections
            List of PE sections with information regarding
            - section name `name`
            - virtual size of section `virtual_size`
            - raw data size of section `raw_data_size`
            - `entropy` of section
          - dlls: list of imported symbols
          - OPTIONAL_HEADER information
            - SizeOfCode
            - SizeOfInitializedData
            - SizeOfUninitializedData
            - SizeOfStackReserve
            - SizeOfStackCommit
            - SizeOfHeapReserve
            - SizeOfHeapCommit
          - FILE_HEADER info
            - NumberOfSections
            - NumberOfSymbols
    """
    filtered_data = {}
    data_dict = {}
    splitted_headers = re.split(b'----------(:?[a-zA-Z _]*)----------', data)
    num_headers = len(splitted_headers)

    for i in range(0, num_headers - 1, 2):
        data_dict[splitted_headers[i + 1]] = splitted_headers[i + 2]

    # PE Sections
    section_list = []
    try:
        for section in re.findall(
            rb'Name:(.*?)\n[\s\S]*?Misc_VirtualSize:(.*?)\n[\s\S]*?SizeOfRawData:(.*?)\n[\s\S]*?Entropy:(.*?)\(',
                data_dict[b'PE Sections']):
            section_data = {}
            section_data['name'] = section[0].strip().decode()
            section_data['virtual_size'] = section[1].strip().decode()
            section_data['raw_data_size'] = section[2].strip().decode()
            section_data['entropy'] = section[3].strip().decode()
            section_list.append(section_data)
    except BaseException:
        pass

    filtered_data['sections'] = section_list
    # dll calls Imported Symbols
    try:
        filtered_data['dlls'] = list(map(lambda x: x.decode(), re.findall(
            rb'(.*)Hint\[', data_dict[b'Imported symbols'])))
    except BaseException:
        filtered_data['dlls'] = []
    # OPTIONAL HEADER
    try:
        filtered_data['SizeOfCode'] = re.findall(
            b'SizeOfCode:(.*)', data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfInitializedData'] = re.findall(
            b'SizeOfInitializedData:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfUninitializedData'] = re.findall(
            b'SizeOfUninitializedData:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfStackReserve'] = re.findall(
            b'SizeOfStackReserve:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfStackCommit'] = re.findall(
            b'SizeOfStackCommit:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfHeapReserve'] = re.findall(
            b'SizeOfHeapReserve:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
        filtered_data['SizeOfHeapCommit'] = re.findall(
            b'SizeOfHeapCommit:(.*)',
            data_dict[b'OPTIONAL_HEADER'])[0].strip().decode()
    except BaseException:
        filtered_data['SizeOfCode'] = []
        filtered_data['SizeOfInitializedData'] = []
        filtered_data['SizeOfUninitializedData'] = []
        filtered_data['SizeOfStackReserve'] = []
        filtered_data['SizeOfStackCommit'] = []
        filtered_data['SizeOfHeapReserve'] = []
        filtered_data['SizeOfHeapCommit'] = []

    # FILE_HEADER
    try:
        filtered_data['NumberOfSections'] = re.findall(
            b'NumberOfSections:(.*)', data_dict[b'FILE_HEADER'])[0].strip().decode()
        filtered_data['NumberOfSymbols'] = re.findall(
            b'NumberOfSymbols:(.*)', data_dict[b'FILE_HEADER'])[0].strip().decode()
    except BaseException:
        filtered_data['NumberOfSections'] = []
        filtered_data['NumberOfSymbols'] = []
    return filtered_data