"""
Validation functions for post-validation checks.
These functions are applied after Pydantic validation (mode='after').
"""

from __future__ import annotations

from typing import Any, Callable

from pydantic import ValidationInfo

from pycharter.shared.validations.builtin import (
    greater_than_or_equal_to,
    is_alphanumeric,
    is_email,
    is_numeric_string,
    is_positive,
    is_unique,
    is_url,
    less_than_or_equal_to,
    matches_regex,
    max_length,
    min_length,
    no_capital_characters,
    no_special_characters,
    non_empty_string,
    only_allow,
    only_allow_if,
)

# Short descriptions and expected arguments for API/UI (Options > Validation tab)
VALIDATION_DESCRIPTIONS: dict[str, str | None] = {
    "min_length": "Value (string, list, or dict) must have at least this many characters or items.",
    "max_length": "Value (string, list, or dict) must have at most this many characters or items.",
    "only_allow": "Value must be one of the allowed values.",
    "only_allow_if": "Conditional only_allow: allow only certain values when another field matches a condition.",
    "greater_than_or_equal_to": "Numeric value must be >= threshold.",
    "less_than_or_equal_to": "Numeric value must be <= threshold.",
    "no_capital_characters": "String must not contain uppercase letters.",
    "no_special_characters": "String must contain only alphanumeric characters and spaces.",
    "is_positive": "Numeric value must be greater than threshold (default 0).",
    "non_empty_string": "String must not be empty (after stripping whitespace).",
    "matches_regex": "String must match the given regular expression pattern.",
    "is_email": "String must be a valid email address.",
    "is_url": "String must be a valid URL (http or https).",
    "is_alphanumeric": "String must contain only letters and digits (no spaces or special chars).",
    "is_numeric_string": "String must represent a number (digits, optional decimal point, optional minus).",
    "is_unique": "All items in the list must be unique.",
}

# Expected arguments per validation (name, type, description, required)
VALIDATION_ARGUMENTS: dict[str, list[dict[str, Any]]] = {
    "min_length": [
        {
            "name": "threshold",
            "type": "int",
            "description": "Minimum length required.",
            "required": True,
        },
    ],
    "max_length": [
        {
            "name": "threshold",
            "type": "int",
            "description": "Maximum length allowed.",
            "required": True,
        },
    ],
    "only_allow": [
        {
            "name": "allowed_values",
            "type": "list",
            "description": "List of allowed values.",
            "required": True,
        },
    ],
    "only_allow_if": [
        {
            "name": "condition",
            "type": "dict",
            "description": "Dict with 'field' and 'value' for conditional check.",
            "required": True,
        },
    ],
    "greater_than_or_equal_to": [
        {
            "name": "threshold",
            "type": "float",
            "description": "Minimum value allowed.",
            "required": True,
        },
    ],
    "less_than_or_equal_to": [
        {
            "name": "threshold",
            "type": "float",
            "description": "Maximum value allowed.",
            "required": True,
        },
    ],
    "no_capital_characters": [],
    "no_special_characters": [],
    "is_positive": [
        {
            "name": "threshold",
            "type": "int",
            "description": "Minimum value (default 0).",
            "required": False,
        },
    ],
    "non_empty_string": [],
    "matches_regex": [
        {
            "name": "pattern",
            "type": "string",
            "description": "Regular expression pattern to match.",
            "required": True,
        },
    ],
    "is_email": [],
    "is_url": [],
    "is_alphanumeric": [],
    "is_numeric_string": [],
    "is_unique": [],
}


def list_validation_functions() -> list[dict[str, Any]]:
    """Return list of supported validation function names, descriptions, and arguments for API/UI."""
    return [
        {
            "name": name,
            "description": VALIDATION_DESCRIPTIONS.get(name, ""),
            "arguments": VALIDATION_ARGUMENTS.get(name, []),
        }
        for name in sorted(VALIDATION_REGISTRY.keys())
    ]


# Registry of available validation functions
VALIDATION_REGISTRY: dict[str, Callable] = {
    "min_length": min_length,
    "max_length": max_length,
    "only_allow": only_allow,
    "only_allow_if": only_allow_if,
    "greater_than_or_equal_to": greater_than_or_equal_to,
    "less_than_or_equal_to": less_than_or_equal_to,
    "no_capital_characters": no_capital_characters,
    "no_special_characters": no_special_characters,
    "is_positive": is_positive,
    "non_empty_string": non_empty_string,
    "matches_regex": matches_regex,
    "is_email": is_email,
    "is_url": is_url,
    "is_alphanumeric": is_alphanumeric,
    "is_numeric_string": is_numeric_string,
    "is_unique": is_unique,
}


def get_validation(name: str) -> Callable:
    """
    Get a validation function factory by name.

    Args:
        name: Name of the validation function

    Returns:
        The validation function factory

    Raises:
        ValueError: If validation function not found
    """
    if name not in VALIDATION_REGISTRY:
        raise ValueError(
            f"Validation function '{name}' not found. "
            f"Available: {list(VALIDATION_REGISTRY.keys())}"
        )
    return VALIDATION_REGISTRY[name]


def register_validation(name: str, func: Callable) -> None:
    """
    Register a custom validation function.

    Args:
        name: Name to register the function under
        func: The validation function factory
    """
    VALIDATION_REGISTRY[name] = func
