"""
Module: /mnt/e/genesis-system/core/knowledge/patterns.py
Description: This module catalogs reusable code patterns from the Genesis codebase,
             providing documented examples for common tasks.  It aims to
             promote code reuse, consistency, and maintainability.
"""

import logging
import traceback
from typing import Callable, TypeVar, Any, List, Dict, Optional

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(module)s - %(message)s'
)

T = TypeVar('T')
R = TypeVar('R')


class PatternLibraryError(Exception):
    """
    Custom exception for errors related to pattern library operations.
    """
    pass


def safe_operation(operation: Callable[..., R], *args: Any, **kwargs: Any) -> Optional[R]:
    """
    Wraps an operation in a try-except block to handle exceptions gracefully.

    Args:
        operation: The callable operation to execute.
        *args: Positional arguments for the operation.
        **kwargs: Keyword arguments for the operation.

    Returns:
        The result of the operation if successful, None otherwise.  The actual return type
        is inferred from the type hint of the `operation`.

    Raises:
        PatternLibraryError: If an unrecoverable error occurs during the operation,
            an PatternLibraryError exception is raised encapsulating the original exception.

    Example:
        result = safe_operation(some_function, arg1, arg2=value)
        if result is not None:
            # Process the result
            ...
        else:
            # Handle the error case
            ...
    """
    try:
        return operation(*args, **kwargs)
    except Exception as e:
        logging.error(f"Error during operation {operation.__name__}: {e}")
        logging.error(traceback.format_exc())  # Log the full traceback
        raise PatternLibraryError(f"Operation failed: {e}") from e # Encapsulate the original exception


def retry_operation(operation: Callable[..., R], max_attempts: int = 3, *args: Any, **kwargs: Any) -> Optional[R]:
    """
    Retries an operation a specified number of times in case of failure.

    Args:
        operation: The callable operation to execute.
        max_attempts: The maximum number of retry attempts. Defaults to 3.
        *args: Positional arguments for the operation.
        **kwargs: Keyword arguments for the operation.

    Returns:
        The result of the operation if successful within the retry limit, None otherwise.
        The actual return type is inferred from the type hint of the `operation`.

    Raises:
        PatternLibraryError: If the operation fails after all retry attempts, a PatternLibraryError
            exception is raised encapsulating the last exception.

    Example:
        result = retry_operation(connect_to_database, max_attempts=5)
        if result is not None:
            # Process the successful connection
            ...
        else:
            # Handle the failure to connect
            ...
    """
    for attempt in range(max_attempts):
        try:
            return operation(*args, **kwargs)
        except Exception as e:
            logging.warning(f"Attempt {attempt + 1}/{max_attempts} failed for {operation.__name__}: {e}")
            if attempt == max_attempts - 1:
                logging.error(f"Operation {operation.__name__} failed after {max_attempts} attempts.")
                logging.error(traceback.format_exc())
                raise PatternLibraryError(f"Operation failed after retries: {e}") from e
            # Consider adding a delay here (e.g., time.sleep(1)) before the next attempt
            # if the operation might benefit from it (e.g., network-related operations).
    return None  # Should not reach here, but included for clarity


def filter_list(data: List[T], condition: Callable[[T], bool]) -> List[T]:
    """
    Filters a list based on a given condition.

    Args:
        data: The list to filter.
        condition: A function that takes an element of the list as input and returns a boolean.

    Returns:
        A new list containing only the elements that satisfy the condition.

    Example:
        numbers = [1, 2, 3, 4, 5, 6]
        even_numbers = filter_list(numbers, lambda x: x % 2 == 0)  # Returns [2, 4, 6]
    """
    try:
        return [item for item in data if condition(item)]
    except Exception as e:
        logging.error(f"Error filtering list: {e}")
        logging.error(traceback.format_exc())
        raise PatternLibraryError(f"List filtering failed: {e}") from e


def map_list(data: List[T], transform: Callable[[T], R]) -> List[R]:
    """
    Applies a transformation function to each element of a list.

    Args:
        data: The list to transform.
        transform: A function that takes an element of the list as input and returns a transformed value.

    Returns:
        A new list containing the transformed elements.

    Example:
        numbers = [1, 2, 3]
        squared_numbers = map_list(numbers, lambda x: x * x)  # Returns [1, 4, 9]
    """
    try:
        return [transform(item) for item in data]
    except Exception as e:
        logging.error(f"Error mapping list: {e}")
        logging.error(traceback.format_exc())
        raise PatternLibraryError(f"List mapping failed: {e}") from e


def update_dict(original: Dict[Any, Any], updates: Dict[Any, Any]) -> Dict[Any, Any]:
    """
    Updates a dictionary with values from another dictionary, creating a new copy.

    Args:
        original: The original dictionary.
        updates: The dictionary containing the updates.

    Returns:
        A new dictionary with the updates applied.

    Example:
        original_dict = {"a": 1, "b": 2}
        updates_dict = {"b": 3, "c": 4}
        updated_dict = update_dict(original_dict, updates_dict) # Returns {"a": 1, "b": 3, "c": 4}
    """
    try:
        new_dict = original.copy()
        new_dict.update(updates)
        return new_dict
    except Exception as e:
        logging.error(f"Error updating dictionary: {e}")
        logging.error(traceback.format_exc())
        raise PatternLibraryError(f"Dictionary update failed: {e}") from e


# Example Usage (Not executed during module import)
if __name__ == '__main__':
    # Example 1: Safe Operation
    def risky_function(x: int) -> int:
        if x == 0:
            raise ValueError("Cannot divide by zero.")
        return 10 / x

    try:
        result = safe_operation(risky_function, 5)
        if result is not None:
            print(f"Safe operation result: {result}")

        safe_operation(risky_function, 0)  # This will raise a PatternLibraryError
    except PatternLibraryError as e:
        print(f"Handled exception: {e}")

    # Example 2: Retry Operation
    def flaky_function() -> bool:
        import random
        if random.random() < 0.5:  # Simulate occasional failure
            raise Exception("Flaky function failed.")
        return True

    try:
        success = retry_operation(flaky_function, max_attempts=3)
        if success:
            print("Flaky function succeeded after retries.")
        else:
            print("Flaky function failed after all retries.")  # This line will not be reached with exception handling.
    except PatternLibraryError as e:
        print(f"Retry operation failed: {e}")

    # Example 3: Filter List
    numbers = [1, 2, 3, 4, 5, 6]
    even_numbers = filter_list(numbers, lambda x: x % 2 == 0)
    print(f"Even numbers: {even_numbers}")

    # Example 4: Map List
    squared_numbers = map_list(numbers, lambda x: x * x)
    print(f"Squared numbers: {squared_numbers}")

    # Example 5: Update Dict
    original_dict = {"a": 1, "b": 2}
    updates_dict = {"b": 3, "c": 4}
    updated_dict = update_dict(original_dict, updates_dict)
    print(f"Updated dictionary: {updated_dict}")