"""Utility functions for VibeDB."""

import json
import time
import uuid
from typing import Any, Dict


def generate_id() -> str:
    """
    Generate a unique document ID.

    Uses UUID4 for simplicity and universal uniqueness.
    Format: lowercase hex without dashes (e.g., "a1b2c3d4e5f6...")

    Returns:
        str: Unique document ID
    """
    return uuid.uuid4().hex


def current_timestamp() -> int:
    """
    Get current Unix timestamp in milliseconds.

    Returns:
        int: Current time in milliseconds since epoch
    """
    return int(time.time() * 1000)


def serialize_value(value: Any) -> Any:
    """
    Serialize Python value to JSON-compatible format.

    Handles special types like datetime, bytes, etc.

    Args:
        value: Python value to serialize

    Returns:
        JSON-compatible value
    """
    # Handle None
    if value is None:
        return None

    # Handle datetime
    if hasattr(value, 'isoformat'):
        return value.isoformat()

    # Handle bytes
    if isinstance(value, bytes):
        return value.hex()

    # Handle sets (convert to list)
    if isinstance(value, set):
        return list(value)

    # Already JSON-compatible
    return value


def serialize_document(doc: Dict[str, Any]) -> str:
    """
    Serialize document dict to JSON string.

    Handles special Python types and ensures consistent formatting.

    Args:
        doc: Document dictionary

    Returns:
        str: JSON string representation
    """
    def default_serializer(obj):
        """Custom serializer for non-standard types."""
        if hasattr(obj, 'isoformat'):  # datetime
            return obj.isoformat()
        if isinstance(obj, bytes):
            return obj.hex()
        if isinstance(obj, set):
            return list(obj)
        raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")

    return json.dumps(doc, default=default_serializer, ensure_ascii=False, separators=(',', ':'))


def deserialize_document(json_str: str) -> Dict[str, Any]:
    """
    Deserialize JSON string to document dict.

    Args:
        json_str: JSON string

    Returns:
        dict: Deserialized document
    """
    if not json_str:
        return {}

    try:
        return json.loads(json_str)
    except json.JSONDecodeError as e:
        raise ValueError(f"Invalid JSON document: {e}")


def safe_field_name(field: str) -> str:
    """
    Ensure field name is safe for SQL operations.

    This prevents SQL injection by validating field names.
    Field names should only contain alphanumeric characters, underscores, and dots.

    Args:
        field: Field name to validate

    Returns:
        str: Original field name if valid

    Raises:
        ValueError: If field name contains invalid characters
    """
    # Allow alphanumeric, underscore, and dot (for nested fields)
    if not all(c.isalnum() or c in ('_', '.') for c in field):
        raise ValueError(
            f"Invalid field name '{field}'. "
            "Field names can only contain letters, numbers, underscores, and dots."
        )

    return field


def format_json_path(field: str) -> str:
    """
    Convert field name to JSON path for SQLite json_extract.

    Examples:
        'name' -> '$.name'
        'address.city' -> '$.address.city'
        'tags[0]' -> '$.tags[0]'

    Args:
        field: Field name (possibly nested)

    Returns:
        str: JSON path string for SQLite
    """
    if not field.startswith('$'):
        return f'$.{field}'
    return field


def validate_document(doc: Any) -> Dict[str, Any]:
    """
    Validate that a value is a valid document (dict).

    Args:
        doc: Value to validate

    Returns:
        dict: The document if valid

    Raises:
        TypeError: If doc is not a dictionary
    """
    if not isinstance(doc, dict):
        raise TypeError(
            f"Document must be a dictionary, got {type(doc).__name__}. "
            f"Example: {{'name': 'Alice', 'age': 28}}"
        )

    return doc


def merge_documents(base: Dict[str, Any], updates: Dict[str, Any]) -> Dict[str, Any]:
    """
    Merge update fields into base document.

    Performs a shallow merge - nested dicts are replaced, not merged.

    Args:
        base: Base document
        updates: Fields to update

    Returns:
        dict: Merged document (new dict, doesn't modify inputs)
    """
    result = base.copy()
    result.update(updates)
    return result
