from typing import Tuple
from typing import Optional


def parse_item_stack(data_in: str, allow_ranges: bool = True) -> Tuple[str, bool, Optional[int], Optional[int]]:
    """
    Allows the following formats to define either an item or a tag:
    'namespace:path' -> item
    '#namespace:path' -> tag
    Also allows the following count specifiers
    '1 item'
    '3-5 item' (only if allow_ranges = True)
    Returns (item name, is tag, minimum count, maximum count)
    """
    item = data_in
    try:
        if ' ' in data_in:
            count, item = data_in.split(' ')
            if '-' in count:
                if not allow_ranges:
                    raise ValueError('Range in item stack with allow_ranges = False')
                lo, hi = map(int, count.split('-'))
            else:
                lo = hi = int(count)
        else:
            lo = hi = None
    except Exception as e:
        raise ValueError('Malformed item stack: %s' % data_in) from e

    if 'tag!' in data_in:
        raise ValueError('Using old \'tag!\' format for item stack: %s' % str(data_in))

    tag = item[0] == '#'
    if tag:
        item = item[1:]

    return item, tag, lo, hi