"""Executable reference for the collection patterns taught in module 02."""

REQUIRED_FIELDS = {"article", "name", "quantity", "unit_price"}


def normalize_article(value):
    """Remove whitespace and normalize letter case without deleting punctuation."""
    return "".join(value.split()).upper()


def missing_fields(position):
    """Return required field names that are absent from a position."""
    return sorted(REQUIRED_FIELDS.difference(position))


def find_by_article(catalog, article):
    """Return the first position with the normalized article, or None."""
    normalized = normalize_article(article)

    for position in catalog:
        stored_article = normalize_article(position["article"])

        if stored_article == normalized:
            return position

    return None


def add_position(catalog, position):
    """Validate, copy, normalize, and append a unique position."""
    if missing_fields(position):
        return False

    stored_position = position.copy()
    stored_position["article"] = normalize_article(stored_position["article"])
    stored_position["name"] = stored_position["name"].strip()

    if stored_position["article"] == "" or stored_position["name"] == "":
        return False

    if find_by_article(catalog, stored_position["article"]) is not None:
        return False

    catalog.append(stored_position)
    return True


def search_by_name(catalog, query):
    """Return positions containing a nonempty case-insensitive name query."""
    normalized_query = query.strip().casefold()

    if normalized_query == "":
        return []

    matches = []

    for position in catalog:
        if normalized_query in position["name"].casefold():
            matches.append(position)

    return matches


def catalog_summary(catalog):
    """Return line count, unit count, and total catalog cost."""
    line_count = len(catalog)
    unit_count = 0
    total_cost = 0

    for position in catalog:
        unit_count += position["quantity"]
        total_cost += position["quantity"] * position["unit_price"]

    return line_count, unit_count, total_cost
