from typing import Tuple
from typing import Set


def parse_product_str(product_str: str) -> Tuple[str, Set[str], str]:
    """Parses provided product string.

    Args:
        product_str: target supplied product string.

    Returns:
        (family, defines, name) where
            `family` is the stm32 product family (ex. 'stm32l5xx')
            `defines` is a list of potential product defines for the HAL.
                There can be multiple because some products use a subfamily
                for their define.
                (ex. The only stm32f411 define is `STM32F411xE`)
                The correct define can be validated using `select_define()`
            `name` is the standardized name for the product string.
                (ex. product_str = 'STM32F429', name = 'stm32f429xx')
                This is the product name expected by the filename matching
                functions (`match_filename()`, etc.)

    Raises:
        ValueError if the product string does not start with 'stm32' or specify
            at least the chip model (9 chars).
    """
    product_name = product_str.lower()
    if not product_name.startswith('stm32'):
        raise ValueError("Product string must start with 'stm32'")

    if len(product_name) < 9:
        raise ValueError(
            "Product string too short. Must specify at least the chip model.")

    family = product_name[:7] + 'xx'
    name = product_name

    # Pad the full name with 'x' to reach the max expected length.
    name = product_name.ljust(11, 'x')

    # This generates all potential define suffixes for a given product name
    # This is required because some boards have more specific defines
    # ex. STM32F411xE, while most others are generic, ex. STM32F439xx
    # So if the user specifies `stm32f207zgt6u`, this should generate the
    # following as potential defines
    #  STM32F207xx, STM32F207Zx, STM32F207xG, STM32F207ZG
    define_suffixes = ['xx']
    if name[9] != 'x':
        define_suffixes.append(name[9].upper() + 'x')
    if name[10] != 'x':
        define_suffixes.append('x' + name[10].upper())
    if name[9] != 'x' and name[10] != 'x':
        define_suffixes.append(name[9:11].upper())

    defines = set(map(lambda x: product_name[:9].upper() + x, define_suffixes))
    return (family, defines, name)