"""Common utility functions for HarnessElo."""

from collections.abc import Sequence
from datetime import date, datetime
from typing import Any


def parse_date(date_str: str) -> date:
    """Parse date string in YYYY-MM-DD format.

    Args:
        date_str: Date string to parse

    Returns:
        Parsed date object

    Raises:
        ValueError: If date string is invalid
    """
    try:
        return datetime.strptime(date_str, "%Y-%m-%d").date()
    except ValueError as e:
        raise ValueError(
            f"Invalid date format '{date_str}', expected YYYY-MM-DD"
        ) from e


def format_date(d: date) -> str:
    """Format date as YYYY-MM-DD string.

    Args:
        d: Date to format

    Returns:
        Formatted date string
    """
    return d.strftime("%Y-%m-%d")


def get_distance_bucket(
    distance_m: int | None,
    buckets: Sequence[int],
    mode: str = "thresholds",
    bucket_size: int | None = None,
) -> str:
    """Get distance bucket label for a given distance.

    Args:
        distance_m: Distance in meters (can be None)
        buckets: List of bucket thresholds in ascending order
        mode: Bucketing mode ("thresholds" or "fixed")
        bucket_size: Fixed bucket size in meters (required if mode is "fixed")

    Returns:
        Bucket label (e.g., "<1700", "1700-2000", ">2400")
    """
    if distance_m is None:
        return "unknown"

    if mode == "fixed":
        if not bucket_size or bucket_size <= 0:
            return "unknown"
        start = (distance_m // bucket_size) * bucket_size
        end = start + bucket_size - 1
        return f"{start}-{end}"

    for i, threshold in enumerate(buckets):
        if distance_m < threshold:
            if i == 0:
                return f"<{threshold}"
            else:
                return f"{buckets[i-1]}-{threshold}"

    # Distance is greater than all thresholds
    return f">{buckets[-1]}"


def safe_get(d: dict[str, Any], *keys: str, default: Any = None) -> Any:
    """Safely get nested dictionary value.

    Args:
        d: Dictionary to query
        *keys: Sequence of keys to traverse
        default: Default value if key path not found

    Returns:
        Value at key path or default

    Example:
        >>> data = {"a": {"b": {"c": 123}}}
        >>> safe_get(data, "a", "b", "c")
        123
        >>> safe_get(data, "a", "x", "y", default=0)
        0
    """
    current = d
    for key in keys:
        if not isinstance(current, dict) or key not in current:
            return default
        current = current[key]
    return current
