import pandas as pd


def validate_enum_constraint(df: pd.DataFrame, constraint: dict, config: dict) -> list:
    """Handler for enum_validation constraint"""
    errors = []
    constraint_config = constraint.get("config", {})
    column = constraint_config.get("column")
    allowed_values = constraint_config.get("allowed_values", [])
    patterns = constraint_config.get("patterns", [])  # Optional list of regex patterns

    if not column or column not in df.columns:
        return errors

    # If patterns specified, use regex validation
    if patterns:
        import re

        compiled_patterns = [re.compile(p) for p in patterns]

        for idx, value in df[column].items():
            if pd.notna(value):
                value_str = str(value)
                # Value is valid if it matches ANY pattern
                if not any(regex.fullmatch(value_str) for regex in compiled_patterns):
                    if len(patterns) == 1:
                        errors.append(
                            f"Device element at index {idx}, column '{column}' has invalid value '{value}'; "
                            f"must match pattern '{patterns[0]}'"
                        )
                    else:
                        errors.append(
                            f"Device element at index {idx}, column '{column}' has invalid value '{value}'; "
                            f"must match one of: {patterns}"
                        )
    # Otherwise use allowed_values list
    elif allowed_values:
        errors.extend(
            validate_enum_column(
                column_values=df[column],
                allowed_values=allowed_values,
                col_name=column,
            )
            or []
        )

    return errors


def validate_enum_column(
    column_values=pd.Series, allowed_values=None, col_name="Column"
):
    """Validate that column values are in the allowed list"""
    errors = []
    if allowed_values is None:
        allowed_values = []

    invalid_mask = ~column_values.isin(allowed_values)
    invalid_values = column_values[invalid_mask]
    for idx, value in invalid_values.items():
        errors.append(
            f"Device element at index {idx}, column '{col_name}' has invalid value '{value}', "
            f"but allowed values are {allowed_values}."
        )
    return errors
