"""
Integration examples showing how to use the error handling system with BaoLife's WebSocket system.

This file provides examples of integrating the error handler with:
- Existing WebSocket communication (sendToUser, sendEventMessage)
- Database operations
- Game state modifications
- Purchase validation
"""

import asyncio
import logging
from typing import Dict, Any
from errors.error_handler import (
    GameError,
    InsufficientResourcesError,
    ServerError,
    handle_errors,
    send_error_to_client
)

logger = logging.getLogger(__name__)


# Example 1: Integration with existing sendToUser pattern
async def example_with_sendToUser(websocket, player, amount: int):
    """
    Example showing integration with app.py's sendToUser function.

    This demonstrates:
    - Using handle_errors decorator with WebSocket sending
    - Validating player resources before operations
    - Automatic error notification to client
    """

    async def send_to_client(player_id, message):
        """Wrapper to match sendToUser signature."""
        import json
        from app import sendToUser
        await sendToUser(websocket, json.dumps(message))

    @handle_errors(send_to_client=send_to_client)
    async def process_energy_purchase(player_id: int, amount: int) -> Dict[str, Any]:
        # Get player money from player object
        player_money = getattr(player.c, 'money', 0)
        cost = amount * 10

        # Validate sufficient funds
        if player_money < cost:
            raise InsufficientResourcesError('money', cost, player_money)

        # Process purchase
        player.c.money -= cost
        player.c.energy += amount

        # Save to database
        from functions import saveGame
        try:
            saveGame(player)
        except Exception as e:
            raise ServerError("Failed to save game", original_exception=e)

        return {
            'success': True,
            'message': f'Purchased {amount} energy for ${cost}',
            'new_balance': player.c.money,
            'new_energy': player.c.energy
        }

    try:
        result = await process_energy_purchase(player.c.id, amount)

        # Send success message to client
        await send_to_client(player.c.id, {
            'type': 'purchaseSuccess',
            'data': result
        })

        return result

    except (GameError, ServerError):
        # Error already logged and sent to client by decorator
        return {'success': False}


# Example 2: Database operation with error handling
@handle_errors()
def load_player_with_error_handling(player_id: int):
    """
    Example of database loading with error handling.

    Demonstrates:
    - Sync function error handling
    - ServerError for database failures
    - Proper exception wrapping
    """
    try:
        from functions import loadGame
        player = loadGame(player_id)

        if not player:
            raise GameError(
                f"Player {player_id} not found",
                error_code='PLAYER_NOT_FOUND',
                retry_possible=False
            )

        return player

    except Exception as e:
        raise ServerError(
            f"Failed to load player {player_id}",
            original_exception=e
        )


# Example 3: Activity validation with custom errors
@handle_errors(log_level='WARNING')
async def validate_activity_requirements(player, activity_type: str, websocket=None) -> bool:
    """
    Validate player can perform an activity.

    Demonstrates:
    - Multiple resource validation
    - Custom error messages
    - Different retry_possible values based on error type
    """

    # Define activity requirements
    requirements = {
        'gym': {'energy': 20, 'money': 10},
        'restaurant': {'energy': 10, 'money': 50},
        'study': {'energy': 15, 'money': 0},
        'socialize': {'energy': 10, 'money': 20}
    }

    if activity_type not in requirements:
        raise GameError(
            f"Unknown activity: {activity_type}",
            error_code='INVALID_ACTIVITY',
            retry_possible=False
        )

    req = requirements[activity_type]

    # Check energy
    if player.c.energy < req['energy']:
        raise InsufficientResourcesError('energy', req['energy'], player.c.energy)

    # Check money
    if player.c.money < req['money']:
        raise InsufficientResourcesError('money', req['money'], player.c.money)

    return True


# Example 4: Diamond purchase validation (monetization integration)
async def handle_diamond_purchase(player_id: int, product_id: str, websocket):
    """
    Example integrating with monetization system.

    Demonstrates:
    - Integration with existing monetization code
    - Rate limiting combined with error handling
    - Idempotency checking
    """
    from monetization.validation import rate_limit

    async def send_to_client(pid, message):
        import json
        from app import sendToUser
        await sendToUser(websocket, json.dumps(message))

    @rate_limit(max_calls=5, time_window=60)
    @handle_errors(send_to_client=send_to_client)
    async def process_purchase(player_id: int, product_id: str):
        # Validate product exists
        valid_products = ['diamonds_small', 'diamonds_medium', 'diamonds_large']
        if product_id not in valid_products:
            raise GameError(
                f"Invalid product: {product_id}",
                error_code='INVALID_PRODUCT',
                retry_possible=False
            )

        # Process purchase through validation system
        from monetization.diamond_economy import award_diamonds

        try:
            diamond_amounts = {
                'diamonds_small': 100,
                'diamonds_medium': 300,
                'diamonds_large': 750
            }

            amount = diamond_amounts[product_id]
            award_diamonds(player_id, f'purchase_{product_id}', amount)

            return {
                'success': True,
                'diamonds_awarded': amount
            }

        except Exception as e:
            raise ServerError(
                "Failed to process diamond purchase",
                original_exception=e
            )

    try:
        result = await process_purchase(player_id, product_id)

        # Send success notification
        await send_to_client(player_id, {
            'type': 'diamondPurchaseSuccess',
            'data': result
        })

        return result

    except (GameError, ServerError):
        # Error already handled by decorator
        return {'success': False}


# Example 5: Time skip validation
@handle_errors()
async def validate_time_skip(player_id: int, hours: int) -> Dict[str, Any]:
    """
    Validate and process time skip purchase.

    Demonstrates:
    - Multiple validation checks
    - Different error types based on failure reason
    - Business logic validation
    """
    from monetization.diamond_economy import get_diamond_balance, spend_diamonds

    # Validate hours is reasonable
    if hours < 1 or hours > 24:
        raise GameError(
            "Time skip must be between 1 and 24 hours",
            error_code='INVALID_TIME_SKIP',
            retry_possible=False
        )

    # Calculate cost
    cost = hours * 10  # 10 diamonds per hour

    # Check diamond balance
    balance = get_diamond_balance(player_id)
    if balance < cost:
        raise InsufficientResourcesError('diamonds', cost, balance)

    # Process time skip
    try:
        spend_diamonds(player_id, f'time_skip_{hours}h', cost)

        return {
            'success': True,
            'hours_skipped': hours,
            'diamonds_spent': cost,
            'new_balance': balance - cost
        }

    except Exception as e:
        raise ServerError(
            "Failed to process time skip",
            original_exception=e
        )


# Example 6: Conversation event error handling
async def handle_conversation_response(player, character_id: int, response_id: str, websocket):
    """
    Handle conversation responses with validation.

    Demonstrates:
    - Validating conversation state
    - Character existence checks
    - Integration with conversation system
    """

    async def send_to_client(player_id, message):
        import json
        from app import sendToUser
        await sendToUser(websocket, json.dumps(message))

    @handle_errors(send_to_client=send_to_client)
    async def process_response(player_id: int):
        # Find character
        character = None
        for person in player.r:
            if person.id == character_id:
                character = person
                break

        if not character:
            raise GameError(
                f"Character {character_id} not found",
                error_code='CHARACTER_NOT_FOUND',
                retry_possible=False
            )

        # Check if conversation is active
        active_conv = None
        for conv in player.conversations:
            if conv.characterID == character_id:
                active_conv = conv
                break

        if not active_conv:
            raise GameError(
                "No active conversation with this character",
                error_code='NO_ACTIVE_CONVERSATION',
                retry_possible=False
            )

        # Validate response ID
        valid_responses = [r.id for r in active_conv.responses]
        if response_id not in valid_responses:
            raise GameError(
                f"Invalid response: {response_id}",
                error_code='INVALID_RESPONSE',
                retry_possible=False
            )

        # Process response...
        return {
            'success': True,
            'character_id': character_id,
            'response_id': response_id
        }

    try:
        result = await process_response(player.c.id)
        return result
    except (GameError, ServerError):
        return {'success': False}


# Example 7: Batch operation with partial failure handling
async def batch_process_daily_quests(player_ids: list, websocket_map: dict):
    """
    Process multiple players with graceful error handling.

    Demonstrates:
    - Batch processing with error isolation
    - Collecting results and errors separately
    - Logging batch operation results
    """
    results = []
    errors = []

    for player_id in player_ids:
        websocket = websocket_map.get(player_id)

        async def send_to_client(pid, message):
            if websocket:
                import json
                from app import sendToUser
                await sendToUser(websocket, json.dumps(message))

        @handle_errors(send_to_client=send_to_client, log_level='WARNING')
        async def process_player_quests(pid: int):
            from retention.daily_quests import award_quest_rewards

            try:
                rewards = award_quest_rewards(pid)
                return {'player_id': pid, 'success': True, 'rewards': rewards}
            except Exception as e:
                raise ServerError(
                    f"Failed to process quests for player {pid}",
                    original_exception=e
                )

        try:
            result = await process_player_quests(player_id)
            results.append(result)
        except (GameError, ServerError) as e:
            errors.append({'player_id': player_id, 'error': str(e)})

    logger.info(
        f"Batch quest processing complete: {len(results)} succeeded, {len(errors)} failed"
    )

    return {
        'success_count': len(results),
        'error_count': len(errors),
        'results': results,
        'errors': errors
    }


# Example 8: Usage in app.py consumer function
async def consumer_integration_example(websocket, message_data):
    """
    Example showing how to integrate with app.py's consumer function.

    Add to app.py consumer():

    elif message['type'] == 'purchaseEnergy':
        try:
            amount = message.get('amount', 10)
            result = await process_energy_purchase_safe(
                websocket,
                playerRecords[websocket.userID],
                amount
            )

            if result['success']:
                await sendUserInfo(playerRecords[websocket.userID], websocket)

        except Exception as e:
            logger.error(f"Energy purchase failed: {e}")
    """

    async def send_to_client(player_id, message):
        import json
        from app import sendToUser
        await sendToUser(websocket, json.dumps(message))

    @handle_errors(send_to_client=send_to_client)
    async def process_message(player_id: int):
        msg_type = message_data.get('type')

        if msg_type == 'purchaseEnergy':
            amount = message_data.get('amount', 10)

            if amount <= 0 or amount > 100:
                raise GameError(
                    "Invalid energy amount (must be 1-100)",
                    error_code='INVALID_AMOUNT',
                    retry_possible=False
                )

            # Process purchase...
            return {'success': True}

        else:
            raise GameError(
                f"Unknown message type: {msg_type}",
                error_code='UNKNOWN_MESSAGE_TYPE',
                retry_possible=False
            )

    # Get player ID from websocket
    player_id = getattr(websocket, 'userID', None)
    if not player_id:
        logger.error("WebSocket missing userID")
        return

    try:
        return await process_message(player_id)
    except (GameError, ServerError):
        # Already logged and sent to client
        pass
