# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['validate_nside', 'mad', 'robust_std', 'setup_logger']

# %% ../nbs/00_core.ipynb 1
import numpy as np
import pandas as pd
from pathlib import Path
from typing import Optional, Union
import logging

# %% ../nbs/00_core.ipynb 2
def validate_nside(nside: int) -> int:
    """Validate that nside is a power of 2.
    
    Args:
        nside: HEALPix resolution parameter
        
    Returns:
        Validated nside value
        
    Raises:
        ValueError: If nside is not a power of 2
        
    Examples:
        >>> validate_nside(64)
        64
        >>> validate_nside(100)
        Traceback (most recent call last):
        ...
        ValueError: nside must be a power of 2, got 100
    """
    if nside <= 0 or (nside & (nside - 1)) != 0:
        raise ValueError(f"nside must be a power of 2, got {nside}")
    return nside

# %% ../nbs/00_core.ipynb 3
def mad(arr: np.ndarray) -> float:
    """Compute Median Absolute Deviation.
    
    Args:
        arr: Input array
        
    Returns:
        MAD value (float)
        
    Examples:
        >>> arr = np.array([1, 2, 3, 4, 5])
        >>> mad(arr)
        1.0
    """
    arr = np.asarray(arr, dtype=float)
    arr = arr[np.isfinite(arr)]
    if arr.size == 0:
        return float("nan")
    return float(np.median(np.abs(arr - np.median(arr))))

# %% ../nbs/00_core.ipynb 4
def robust_std(arr: np.ndarray) -> float:
    """Compute robust standard deviation using MAD * 1.4826.
    
    The factor 1.4826 makes MAD consistent with standard deviation
    for normally distributed data.
    
    Args:
        arr: Input array
        
    Returns:
        Robust standard deviation (float)
        
    Examples:
        >>> arr = np.array([1, 2, 3, 4, 5])
        >>> robust_std(arr)
        1.4826
    """
    return mad(arr) * 1.4826

# %% ../nbs/00_core.ipynb 5
def setup_logger(name: str, level: int = logging.INFO) -> logging.Logger:
    """Setup a logger with standard formatting.
    
    Args:
        name: Logger name
        level: Logging level (default: INFO)
        
    Returns:
        Configured logger
    """
    logger = logging.getLogger(name)
    logger.setLevel(level)
    
    if not logger.handlers:
        handler = logging.StreamHandler()
        handler.setFormatter(
            logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        )
        logger.addHandler(handler)
    
    return logger
