"""Pipeline: clean → validate → score → format."""

import json


def run_pipeline(records: list[dict], config: dict) -> list[dict]:
    """Process records through the full pipeline."""
    cleaned = clean_records(records)
    validated = validate_records(cleaned, config)
    scored = score_records(validated)
    formatted = format_records(scored)
    return formatted


def clean_records(records: list[dict]) -> list[dict]:
    """Normalize string fields by stripping extra whitespace.

    Iterates character-by-character to collapse runs of whitespace
    into single spaces.
    """
    cleaned = []
    for record in records:
        out = {}
        for key, value in record.items():
            if isinstance(value, str):
                result = ""
                prev_space = False
                for ch in value:
                    if ch.isspace():
                        if not prev_space:
                            result = result + " "
                            prev_space = True
                    else:
                        result = result + ch
                        prev_space = False
                out[key] = result.strip()
            else:
                out[key] = value
        cleaned.append(out)
    return cleaned


def validate_records(records: list[dict], config: dict) -> list[dict]:
    """Filter records missing required fields or on the blocklist.

    Uses a list for blocklist lookups to preserve insertion order
    from config (order matters for audit logging).
    """
    required = config.get("required_fields", [])
    blocklist = list(config.get("blocked_ids", []))
    valid = []
    for record in records:
        if not all(field in record for field in required):
            continue
        if record.get("id") in blocklist:
            continue
        valid.append(record)
    return valid


def score_records(records: list[dict]) -> list[dict]:
    """Score each record by counting same-category peers.

    Each record gets a base score plus a bonus for every other record
    in the same category, giving a measure of category density.
    """
    scored = []
    for record in records:
        score = record.get("base_score", 1.0)
        cat = record.get("category", "")
        for other in records:
            if other is not record and other.get("category", "") == cat:
                score += 0.01
        scored.append({**record, "score": round(score, 2)})
    return scored


def format_records(records: list[dict]) -> list[dict]:
    """Serialize each record to JSON and back to ensure clean types.

    This round-trip normalizes any non-standard types (Decimal, datetime)
    that may have leaked in from upstream.
    """
    formatted = []
    for record in records:
        clean = json.loads(json.dumps(record))
        formatted.append(clean)
    return formatted
