"""JSON serialization utilities for converting pandas objects to JSON-compatible formats."""

from typing import Any, Union
import pandas as pd
import numpy as np
from datetime import datetime, date


def serialize_value(obj: Any) -> Any:
    """Convert complex objects to JSON-compatible format.
    
    This function handles the conversion of various Python and pandas types
    to formats that can be serialized to JSON. It's particularly useful for
    handling numpy types, pandas Timestamps, and NaN values.
    
    Args:
        obj: Any Python object to serialize
        
    Returns:
        JSON-compatible representation of the object
    """
    # Handle None and NaN
    if obj is None:
        return None
    if isinstance(obj, float) and np.isnan(obj):
        return None
    if pd.isna(obj):
        return None
    
    # Handle numpy integer types
    if isinstance(obj, (np.integer,)):
        return int(obj)
    
    # Handle numpy float types
    if isinstance(obj, (np.floating,)):
        return float(obj)
    
    # Handle numpy arrays
    if isinstance(obj, np.ndarray):
        return obj.tolist()
    
    # Handle datetime types
    if isinstance(obj, pd.Timestamp):
        return obj.isoformat()
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    
    # Handle pandas Period
    if isinstance(obj, pd.Period):
        return str(obj)
    
    # Handle pandas Timedelta
    if isinstance(obj, pd.Timedelta):
        return str(obj)
    
    return obj


def df_to_json(df: Union[pd.DataFrame, None]) -> dict:
    """Convert a pandas DataFrame to a JSON-compatible dictionary.
    
    This function converts a DataFrame to a dictionary format suitable for
    JSON serialization. It handles index conversion, NaN values, and various
    column types.
    
    Args:
        df: DataFrame to convert, or None
        
    Returns:
        Dictionary with 'data' (list of records) and 'columns' (list of column names)
        
    Example:
        >>> df = pd.DataFrame({'A': [1, 2], 'B': ['x', 'y']})
        >>> result = df_to_json(df)
        >>> result['data']
        [{'index': 0, 'A': 1, 'B': 'x'}, {'index': 1, 'A': 2, 'B': 'y'}]
    """
    if df is None:
        return {"data": [], "columns": [], "index_name": None}
    
    if df.empty:
        return {
            "data": [],
            "columns": list(df.columns),
            "index_name": df.index.name
        }
    
    # Reset index to include it in the data
    df_reset = df.reset_index()
    
    # Convert to records
    records = df_reset.to_dict(orient='records')
    
    # Serialize each value in the records
    for record in records:
        for key, value in record.items():
            record[key] = serialize_value(value)
    
    return {
        "data": records,
        "columns": list(df.columns),
        "index_name": df.index.name
    }


def series_to_json(series: Union[pd.Series, None]) -> dict:
    """Convert a pandas Series to a JSON-compatible dictionary.
    
    Args:
        series: Series to convert, or None
        
    Returns:
        Dictionary with 'data' (list of records with index and value),
        'name' (series name), and 'index_name'
    """
    if series is None:
        return {"data": [], "name": None, "index_name": None}
    
    if series.empty:
        return {
            "data": [],
            "name": series.name,
            "index_name": series.index.name
        }
    
    # Convert to DataFrame for consistent handling
    df = series.reset_index()
    df.columns = ['index', 'value'] if series.name is None else ['index', series.name]
    
    records = df.to_dict(orient='records')
    for record in records:
        for key, value in record.items():
            record[key] = serialize_value(value)
    
    return {
        "data": records,
        "name": series.name,
        "index_name": series.index.name
    }


def dict_to_json(d: Union[dict, None]) -> dict:
    """Recursively convert a dictionary to JSON-compatible format.
    
    Args:
        d: Dictionary to convert, or None
        
    Returns:
        Dictionary with all values serialized
    """
    if d is None:
        return {}
    
    result = {}
    for key, value in d.items():
        if isinstance(value, dict):
            result[key] = dict_to_json(value)
        elif isinstance(value, (pd.DataFrame,)):
            result[key] = df_to_json(value)
        elif isinstance(value, (pd.Series,)):
            result[key] = series_to_json(value)
        elif isinstance(value, (list, tuple)):
            result[key] = [serialize_value(v) for v in value]
        else:
            result[key] = serialize_value(value)
    
    return result
