"""
Shared utilities for runtime validation.
"""

from __future__ import annotations

import copy
from typing import Any


def merge_rules_into_schema(
    schema: dict[str, Any],
    coercion_rules: dict[str, Any] | None = None,
    validation_rules: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """
    Merge coercion and validation rules into a schema dictionary.

    This function deep copies the schema and merges rules into the properties.
    Coercion rules are added as a "coercion" field, while validation rules
    are merged directly into each property.

    Args:
        schema: Schema dictionary (will be deep copied)
        coercion_rules: Optional coercion rules dictionary mapping field names to coercion types
        validation_rules: Optional validation rules dictionary mapping field names to rule configs

    Returns:
        Complete schema with rules merged into properties

    Example:
        >>> schema = {"properties": {"age": {"type": "integer"}}}
        >>> coercion_rules = {"age": "coerce_to_integer"}
        >>> validation_rules = {"age": {"greater_than_or_equal_to": {"threshold": 0}}}
        >>> merged = merge_rules_into_schema(schema, coercion_rules, validation_rules)
        >>> merged["properties"]["age"]["coercion"]
        'coerce_to_integer'
    """
    complete_schema = copy.deepcopy(schema)

    # Early return if no rules to merge
    if not coercion_rules and not validation_rules:
        return complete_schema

    # Early return if schema has no properties
    if "properties" not in complete_schema:
        return complete_schema

    properties = complete_schema["properties"]

    # Merge coercion rules
    if coercion_rules:
        for field_name, coercion_name in coercion_rules.items():
            if field_name in properties:
                properties[field_name]["coercion"] = coercion_name

    # Merge validation rules
    if validation_rules:
        for field_name, rule_config in validation_rules.items():
            if field_name not in properties:
                continue

            if isinstance(rule_config, dict):
                # Merge each rule into the property
                for rule_name, rule_params in rule_config.items():
                    # Normalize None to empty dict for consistency
                    properties[field_name][rule_name] = (
                        rule_params if rule_params is not None else {}
                    )
            else:
                # Single validation rule (legacy format)
                properties[field_name]["validation"] = rule_config

    return complete_schema


def get_merged_schema_from_contract(contract: dict[str, Any]) -> dict[str, Any]:
    """
    Get merged schema from a contract dictionary.

    This is a convenience function for cases where you need the merged schema
    (e.g., for display, documentation generation, or legacy code).

    For validation, prefer using the Validator class which handles merging
    internally.

    Args:
        contract: Contract dictionary with 'schema', 'coercion_rules', 'validation_rules' keys

    Returns:
        Schema dictionary with coercion and validation rules merged into properties

    Example:
        >>> contract = build_contract(artifacts)
        >>> merged = get_merged_schema_from_contract(contract)
        >>> merged["properties"]["age"]["coercion"]  # Rules are now in schema
        'coerce_to_integer'

    Note:
        The returned schema is a deep copy - modifications won't affect the
        original contract.
    """
    schema = contract.get("schema", {})
    coercion_rules = contract.get("coercion_rules", {})
    validation_rules = contract.get("validation_rules", {})

    return merge_rules_into_schema(schema, coercion_rules, validation_rules)
