"""
Inventory API Blueprint

Endpoints for managing character inventory and equipment.
All endpoints require authentication and enforce ownership validation.

Endpoints:
- GET /api/v1/characters/<id>/inventory - Get character inventory and equipped items
- POST /api/v1/characters/<id>/inventory/equip - Equip an item
- POST /api/v1/characters/<id>/inventory/unequip - Unequip an item
- POST /api/v1/characters/<id>/inventory/use - Use a consumable item
- DELETE /api/v1/characters/<id>/inventory/<item_id> - Drop an item
"""

from flask import Blueprint, request

from app.services.inventory_service import (
    get_inventory_service,
    ItemNotFoundError,
    CannotEquipError,
    InvalidSlotError,
    CannotUseItemError,
    InventoryFullError,
    VALID_SLOTS,
    MAX_INVENTORY_SIZE,
)
from app.services.character_service import (
    get_character_service,
    CharacterNotFound,
)
from app.utils.response import (
    success_response,
    error_response,
    not_found_response,
    validation_error_response,
)
from app.utils.auth import require_auth, get_current_user
from app.utils.logging import get_logger


# Initialize logger
logger = get_logger(__file__)

# Create blueprint
inventory_bp = Blueprint('inventory', __name__)


# =============================================================================
# API Endpoints
# =============================================================================

@inventory_bp.route('/api/v1/characters/<character_id>/inventory', methods=['GET'])
@require_auth
def get_inventory(character_id: str):
    """
    Get character inventory and equipped items.

    Args:
        character_id: Character ID

    Returns:
        200: Inventory and equipment data
        401: Not authenticated
        404: Character not found or not owned by user
        500: Internal server error

    Example Response:
        {
            "result": {
                "inventory": [
                    {
                        "item_id": "gen_abc123",
                        "name": "Flaming Dagger",
                        "item_type": "weapon",
                        "rarity": "rare",
                        ...
                    }
                ],
                "equipped": {
                    "weapon": {...},
                    "helmet": null,
                    ...
                },
                "inventory_count": 5,
                "max_inventory": 100
            }
        }
    """
    try:
        user = get_current_user()
        logger.info("Getting inventory",
                   user_id=user.id,
                   character_id=character_id)

        # Get character (validates ownership)
        char_service = get_character_service()
        character = char_service.get_character(character_id, user.id)

        # Get inventory service
        inventory_service = get_inventory_service()

        # Get inventory items
        inventory_items = inventory_service.get_inventory(character)

        # Get equipped items
        equipped_items = inventory_service.get_equipped_items(character)

        # Build equipped dict with all slots (None for empty slots)
        equipped_response = {}
        for slot in VALID_SLOTS:
            item = equipped_items.get(slot)
            equipped_response[slot] = item.to_dict() if item else None

        logger.info("Inventory retrieved successfully",
                   user_id=user.id,
                   character_id=character_id,
                   item_count=len(inventory_items))

        return success_response(
            result={
                "inventory": [item.to_dict() for item in inventory_items],
                "equipped": equipped_response,
                "inventory_count": len(inventory_items),
                "max_inventory": MAX_INVENTORY_SIZE,
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except Exception as e:
        logger.error("Failed to get inventory",
                    user_id=user.id if 'user' in locals() else 'unknown',
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="INVENTORY_GET_ERROR",
            message="Failed to retrieve inventory",
            status=500
        )


@inventory_bp.route('/api/v1/characters/<character_id>/inventory/equip', methods=['POST'])
@require_auth
def equip_item(character_id: str):
    """
    Equip an item from inventory to a specified slot.

    Args:
        character_id: Character ID

    Request Body:
        {
            "item_id": "gen_abc123",
            "slot": "weapon"
        }

    Returns:
        200: Item equipped successfully
        400: Cannot equip item (wrong type, level requirement, etc.)
        401: Not authenticated
        404: Character or item not found
        422: Validation error (invalid slot)
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Equipped Flaming Dagger to weapon slot",
                "equipped": {...},
                "unequipped_item": null
            }
        }
    """
    try:
        user = get_current_user()

        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response(
                message="Request body is required",
                details={"error": "Request body is required"}
            )

        item_id = data.get('item_id', '').strip()
        slot = data.get('slot', '').strip().lower()

        # Validate required fields
        validation_errors = {}

        if not item_id:
            validation_errors['item_id'] = "item_id is required"

        if not slot:
            validation_errors['slot'] = "slot is required"

        if validation_errors:
            return validation_error_response(
                message="Validation failed",
                details=validation_errors
            )

        logger.info("Equipping item",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id,
                   slot=slot)

        # Get character (validates ownership)
        char_service = get_character_service()
        character = char_service.get_character(character_id, user.id)

        # Get inventory service
        inventory_service = get_inventory_service()

        # Equip item
        previous_item = inventory_service.equip_item(
            character, item_id, slot, user.id
        )

        # Get item name for message
        equipped_item = character.equipped.get(slot)
        item_name = equipped_item.get_display_name() if equipped_item else item_id

        # Build equipped response
        equipped_response = {}
        for s in VALID_SLOTS:
            item = character.equipped.get(s)
            equipped_response[s] = item.to_dict() if item else None

        logger.info("Item equipped successfully",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id,
                   slot=slot,
                   previous_item=previous_item.item_id if previous_item else None)

        return success_response(
            result={
                "message": f"Equipped {item_name} to {slot} slot",
                "equipped": equipped_response,
                "unequipped_item": previous_item.to_dict() if previous_item else None,
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for equip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except ItemNotFoundError as e:
        logger.warning("Item not found for equip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      item_id=item_id if 'item_id' in locals() else 'unknown',
                      error=str(e))
        return not_found_response(message=str(e))

    except InvalidSlotError as e:
        logger.warning("Invalid slot for equip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      slot=slot if 'slot' in locals() else 'unknown',
                      error=str(e))
        return validation_error_response(
            message=str(e),
            details={"slot": str(e)}
        )

    except CannotEquipError as e:
        logger.warning("Cannot equip item",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      item_id=item_id if 'item_id' in locals() else 'unknown',
                      error=str(e))
        return error_response(
            code="CANNOT_EQUIP",
            message=str(e),
            status=400
        )

    except Exception as e:
        logger.error("Failed to equip item",
                    user_id=user.id if 'user' in locals() else 'unknown',
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="EQUIP_ERROR",
            message="Failed to equip item",
            status=500
        )


@inventory_bp.route('/api/v1/characters/<character_id>/inventory/unequip', methods=['POST'])
@require_auth
def unequip_item(character_id: str):
    """
    Unequip an item from a specified slot (returns to inventory).

    Args:
        character_id: Character ID

    Request Body:
        {
            "slot": "weapon"
        }

    Returns:
        200: Item unequipped successfully (or slot was empty)
        400: Inventory full, cannot unequip
        401: Not authenticated
        404: Character not found
        422: Validation error (invalid slot)
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Unequipped Flaming Dagger from weapon slot",
                "unequipped_item": {...},
                "equipped": {...}
            }
        }
    """
    try:
        user = get_current_user()

        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response(
                message="Request body is required",
                details={"error": "Request body is required"}
            )

        slot = data.get('slot', '').strip().lower()

        if not slot:
            return validation_error_response(
                message="Validation failed",
                details={"slot": "slot is required"}
            )

        logger.info("Unequipping item",
                   user_id=user.id,
                   character_id=character_id,
                   slot=slot)

        # Get character (validates ownership)
        char_service = get_character_service()
        character = char_service.get_character(character_id, user.id)

        # Get inventory service
        inventory_service = get_inventory_service()

        # Unequip item
        unequipped_item = inventory_service.unequip_item(character, slot, user.id)

        # Build equipped response
        equipped_response = {}
        for s in VALID_SLOTS:
            item = character.equipped.get(s)
            equipped_response[s] = item.to_dict() if item else None

        # Build message
        if unequipped_item:
            message = f"Unequipped {unequipped_item.get_display_name()} from {slot} slot"
        else:
            message = f"Slot '{slot}' was already empty"

        logger.info("Item unequipped",
                   user_id=user.id,
                   character_id=character_id,
                   slot=slot,
                   unequipped_item=unequipped_item.item_id if unequipped_item else None)

        return success_response(
            result={
                "message": message,
                "unequipped_item": unequipped_item.to_dict() if unequipped_item else None,
                "equipped": equipped_response,
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for unequip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except InvalidSlotError as e:
        logger.warning("Invalid slot for unequip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      slot=slot if 'slot' in locals() else 'unknown',
                      error=str(e))
        return validation_error_response(
            message=str(e),
            details={"slot": str(e)}
        )

    except InventoryFullError as e:
        logger.warning("Inventory full, cannot unequip",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return error_response(
            code="INVENTORY_FULL",
            message=str(e),
            status=400
        )

    except Exception as e:
        logger.error("Failed to unequip item",
                    user_id=user.id if 'user' in locals() else 'unknown',
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="UNEQUIP_ERROR",
            message="Failed to unequip item",
            status=500
        )


@inventory_bp.route('/api/v1/characters/<character_id>/inventory/use', methods=['POST'])
@require_auth
def use_item(character_id: str):
    """
    Use a consumable item from inventory.

    Args:
        character_id: Character ID

    Request Body:
        {
            "item_id": "health_potion_small"
        }

    Returns:
        200: Item used successfully
        400: Cannot use item (not consumable)
        401: Not authenticated
        404: Character or item not found
        500: Internal server error

    Example Response:
        {
            "result": {
                "item_used": "Small Health Potion",
                "effects_applied": [
                    {
                        "effect_name": "Healing",
                        "effect_type": "hot",
                        "value": 25,
                        "message": "Restored 25 HP"
                    }
                ],
                "hp_restored": 25,
                "mp_restored": 0,
                "message": "Used Small Health Potion: Restored 25 HP"
            }
        }
    """
    try:
        user = get_current_user()

        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response(
                message="Request body is required",
                details={"error": "Request body is required"}
            )

        item_id = data.get('item_id', '').strip()

        if not item_id:
            return validation_error_response(
                message="Validation failed",
                details={"item_id": "item_id is required"}
            )

        logger.info("Using item",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id)

        # Get character (validates ownership)
        char_service = get_character_service()
        character = char_service.get_character(character_id, user.id)

        # Get inventory service
        inventory_service = get_inventory_service()

        # Use consumable
        result = inventory_service.use_consumable(character, item_id, user.id)

        logger.info("Item used successfully",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id,
                   hp_restored=result.hp_restored,
                   mp_restored=result.mp_restored)

        return success_response(result=result.to_dict())

    except CharacterNotFound as e:
        logger.warning("Character not found for use item",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except ItemNotFoundError as e:
        logger.warning("Item not found for use",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      item_id=item_id if 'item_id' in locals() else 'unknown',
                      error=str(e))
        return not_found_response(message=str(e))

    except CannotUseItemError as e:
        logger.warning("Cannot use item",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      item_id=item_id if 'item_id' in locals() else 'unknown',
                      error=str(e))
        return error_response(
            code="CANNOT_USE_ITEM",
            message=str(e),
            status=400
        )

    except Exception as e:
        logger.error("Failed to use item",
                    user_id=user.id if 'user' in locals() else 'unknown',
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="USE_ITEM_ERROR",
            message="Failed to use item",
            status=500
        )


@inventory_bp.route('/api/v1/characters/<character_id>/inventory/<item_id>', methods=['DELETE'])
@require_auth
def drop_item(character_id: str, item_id: str):
    """
    Drop (remove) an item from inventory.

    Args:
        character_id: Character ID
        item_id: Item ID to drop

    Returns:
        200: Item dropped successfully
        401: Not authenticated
        404: Character or item not found
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Dropped Rusty Sword",
                "dropped_item": {...},
                "inventory_count": 4
            }
        }
    """
    try:
        user = get_current_user()

        logger.info("Dropping item",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id)

        # Get character (validates ownership)
        char_service = get_character_service()
        character = char_service.get_character(character_id, user.id)

        # Get inventory service
        inventory_service = get_inventory_service()

        # Drop item
        dropped_item = inventory_service.drop_item(character, item_id, user.id)

        logger.info("Item dropped successfully",
                   user_id=user.id,
                   character_id=character_id,
                   item_id=item_id,
                   item_name=dropped_item.get_display_name())

        return success_response(
            result={
                "message": f"Dropped {dropped_item.get_display_name()}",
                "dropped_item": dropped_item.to_dict(),
                "inventory_count": len(character.inventory),
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for drop",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except ItemNotFoundError as e:
        logger.warning("Item not found for drop",
                      user_id=user.id if 'user' in locals() else 'unknown',
                      character_id=character_id,
                      item_id=item_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except Exception as e:
        logger.error("Failed to drop item",
                    user_id=user.id if 'user' in locals() else 'unknown',
                    character_id=character_id,
                    item_id=item_id,
                    error=str(e))
        return error_response(
            code="DROP_ITEM_ERROR",
            message="Failed to drop item",
            status=500
        )
