from datetime import date, datetime
from typing import Any, Dict, get_origin, get_args, Union
from types import UnionType
import sys


def _unwrap_optional(annotation: Any) -> Any:
    """Return the inner type of Optional[X] / Union[X, None], or the annotation unchanged."""
    origin = get_origin(annotation)
    if origin is Union or origin is UnionType:
        args = [a for a in get_args(annotation) if a is not type(None)]
        return args[0] if args else annotation
    return annotation


def inject_missing_bools(params: Dict[str, Any], annotations: Dict[str, Any]) -> None:
    """Inject False for any bool-typed field absent from POST data.

    HTML checkboxes are omitted entirely when unchecked, so unchecked bool
    fields never appear in ``request.form()``.  Call this after
    ``params = dict(await request.form())`` to normalise the dict before
    passing it to a Pydantic model or a plain function.

    Args:
        params: mutable dict built from ``request.form()`` — modified in place.
        annotations: mapping of field/parameter name → type annotation.
    """
    for name, annotation in annotations.items():
        if _unwrap_optional(annotation) is bool and name not in params:
            params[name] = False


def convert_param_type(param_type, value):
    # Handle Union types (like Optional[int] or int | None)
    origin = get_origin(param_type)
    if origin is Union or origin is UnionType:
        # Get all non-None types in the Union
        args = [arg for arg in get_args(param_type) if arg is not type(None)]
        if args:
            # Use the first type for conversion (as a best effort)
            param_type = args[0]

    if param_type == 'int' or param_type == int:
        return int(value)
    elif param_type == 'float' or param_type == float:
        return float(value)
    elif param_type == 'bool' or param_type == bool:
        if type(value) is bool:
            return bool(value)
        return str(value).lower() in ('true', '1', 'y', 'on', 'yes')
    elif param_type == date:
        if isinstance(value, date):
            return value
        return date.fromisoformat(value)
    elif param_type == datetime:
        if isinstance(value, datetime):
            return value
        return datetime.fromisoformat(value)
    else:
        return value  # Default is string
