"""Deterministic detection of contradictory extracted values within a cluster.

Extraction is a vision pass: quantities and sizes can be misread ("(2) 2x6" vs
"(5) 2x6"). Cluster members are supposed to describe the same real-world
element, so two members asserting different values for the same attribute are
a probable misread. Flag these so downstream text-only stages treat the value
as unverified instead of reasoning from one reading.
"""

import re
from typing import Dict, List


def _norm(value) -> str:
    return re.sub(r"\s+", " ", ("" if value is None else str(value)).strip().lower())


def find_disputes(assertions: List[Dict]) -> List[Dict]:
    """Same attribute with >= 2 distinct normalized values = disputed."""
    groups: Dict[str, Dict[str, Dict]] = {}
    for assertion in assertions:
        attribute = _norm(assertion.get("attribute"))
        value = _norm(assertion.get("value"))
        if not attribute or not value:
            continue
        # Group on the normalized value, but keep the original (whitespace-
        # collapsed) text so disputes read like the sheet, not a lowercase munge.
        original = re.sub(r"\s+", " ", str(assertion.get("value")).strip())
        bucket = groups.setdefault(attribute, {}).setdefault(
            value, {"original": original, "ids": set()}
        )
        bucket["ids"].add(assertion.get("id"))
    disputes = []
    for attribute, values in sorted(groups.items()):
        if len(values) < 2:
            continue
        disputes.append({
            "attribute": attribute,
            "values": sorted(v["original"] for v in values.values()),
            "assertion_ids": sorted(
                aid for v in values.values() for aid in v["ids"] if aid
            ),
        })
    return disputes


def annotate_clusters(clusters: List[Dict]) -> int:
    """Attach disputed_attributes to each cluster that has any. Returns count."""
    annotated = 0
    for cluster in clusters:
        disputes = find_disputes(cluster.get("assertions") or [])
        if disputes:
            cluster["disputed_attributes"] = disputes
            annotated += 1
    return annotated
