"""Field-level preprocessing functions for record linkage."""

from __future__ import annotations

import re
import unicodedata
from typing import Callable, Dict, List

import pandas as pd


def lowercase(series: pd.Series) -> pd.Series:
    """Convert to lowercase."""
    return series.astype(str).str.lower()


def strip_whitespace(series: pd.Series) -> pd.Series:
    """Strip leading/trailing whitespace and collapse internal whitespace."""
    return series.astype(str).str.strip().str.replace(r"\s+", " ", regex=True)


def remove_punctuation(series: pd.Series) -> pd.Series:
    """Remove all punctuation characters."""
    return series.astype(str).str.replace(r"[^\w\s]", "", regex=True)


def normalize_unicode(series: pd.Series) -> pd.Series:
    """NFKD normalization and strip accents."""
    def _normalize(s: str) -> str:
        nfkd = unicodedata.normalize("NFKD", s)
        return "".join(c for c in nfkd if not unicodedata.combining(c))
    return series.astype(str).apply(_normalize)


# Registry of named preprocessing functions
PREPROCESS_REGISTRY: Dict[str, Callable[[pd.Series], pd.Series]] = {
    "lowercase": lowercase,
    "strip": strip_whitespace,
    "strip_whitespace": strip_whitespace,
    "remove_punctuation": remove_punctuation,
    "normalize_unicode": normalize_unicode,
}


def apply_preprocess(series: pd.Series, steps: List[str]) -> pd.Series:
    """Apply a sequence of named preprocessing steps to a series."""
    result = series
    for step in steps:
        if step not in PREPROCESS_REGISTRY:
            raise ValueError(
                f"Unknown preprocess step '{step}'. "
                f"Choose from: {list(PREPROCESS_REGISTRY.keys())}"
            )
        result = PREPROCESS_REGISTRY[step](result)
    return result
