"""
Character API Blueprint

This module provides API endpoints for character management:
- List user's characters
- Get character details
- Create new character
- Delete character
- Unlock skills
- Respec skills

All endpoints require authentication and enforce ownership validation.
"""

from flask import Blueprint, request

from app.services.character_service import (
    get_character_service,
    CharacterLimitExceeded,
    CharacterNotFound,
    SkillUnlockError,
    InsufficientGold
)
from app.services.class_loader import get_class_loader
from app.services.origin_service import get_origin_service
from app.utils.response import (
    success_response,
    created_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
characters_bp = Blueprint('characters', __name__)


# ===== VALIDATION FUNCTIONS =====

def validate_character_name(name: str) -> tuple[bool, str]:
    """
    Validate character name.

    Args:
        name: Character name to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not name:
        return False, "Character name is required"

    if len(name) < 2:
        return False, "Character name must be at least 2 characters"

    if len(name) > 50:
        return False, "Character name must be no more than 50 characters"

    # Allow letters, spaces, hyphens, apostrophes, and common fantasy characters
    if not all(c.isalnum() or c in " -'" for c in name):
        return False, "Character name can only contain letters, numbers, spaces, hyphens, and apostrophes"

    return True, ""


def validate_class_id(class_id: str) -> tuple[bool, str]:
    """
    Validate class ID.

    Args:
        class_id: Class ID to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not class_id:
        return False, "Class ID is required"

    valid_classes = [
        'vanguard', 'assassin', 'arcanist', 'luminary',
        'wildstrider', 'oathkeeper', 'necromancer', 'lorekeeper'
    ]

    if class_id not in valid_classes:
        return False, f"Invalid class ID. Must be one of: {', '.join(valid_classes)}"

    return True, ""


def validate_origin_id(origin_id: str) -> tuple[bool, str]:
    """
    Validate origin ID.

    Args:
        origin_id: Origin ID to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not origin_id:
        return False, "Origin ID is required"

    valid_origins = [
        'soul_revenant', 'memory_thief', 'shadow_apprentice', 'escaped_captive'
    ]

    if origin_id not in valid_origins:
        return False, f"Invalid origin ID. Must be one of: {', '.join(valid_origins)}"

    return True, ""


def validate_skill_id(skill_id: str) -> tuple[bool, str]:
    """
    Validate skill ID.

    Args:
        skill_id: Skill ID to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not skill_id:
        return False, "Skill ID is required"

    if len(skill_id) > 100:
        return False, "Skill ID is too long"

    return True, ""


# ===== API ENDPOINTS =====

@characters_bp.route('/api/v1/characters', methods=['GET'])
@require_auth
def list_characters():
    """
    List all characters owned by the current user.

    Returns:
        200: List of characters
        401: Not authenticated
        500: Internal server error

    Example Response:
        {
            "result": {
                "characters": [
                    {
                        "character_id": "char_001",
                        "name": "Thorin Ironheart",
                        "class": "warrior",
                        "level": 5,
                        "gold": 1000
                    }
                ],
                "count": 1,
                "tier": "free",
                "limit": 1
            }
        }
    """
    try:
        user = get_current_user()
        logger.info("Listing characters", user_id=user.id)

        # Get character service
        char_service = get_character_service()

        # Get user's characters
        characters = char_service.get_user_characters(user.id)

        # Get tier information
        tier = user.tier
        from app.services.character_service import CHARACTER_LIMITS
        limit = CHARACTER_LIMITS.get(tier, 1)

        # Convert characters to dict format
        character_list = [
            {
                "character_id": char.character_id,
                "name": char.name,
                "class": char.player_class.class_id,
                "class_name": char.player_class.name,
                "level": char.level,
                "experience": char.experience,
                "gold": char.gold,
                "current_location": char.current_location,
                "origin": char.origin.id
            }
            for char in characters
        ]

        logger.info("Characters listed successfully",
                   user_id=user.id,
                   count=len(characters))

        return success_response(
            result={
                "characters": character_list,
                "count": len(characters),
                "tier": tier,
                "limit": limit
            }
        )

    except Exception as e:
        logger.error("Failed to list characters",
                    user_id=user.id if user else 'unknown',
                    error=str(e))
        return error_response(
            code="CHARACTER_LIST_ERROR",
            message="Failed to retrieve characters",
            status=500
        )


@characters_bp.route('/api/v1/characters/<character_id>', methods=['GET'])
@require_auth
def get_character(character_id: str):
    """
    Get detailed information about a specific character.

    Args:
        character_id: Character ID

    Returns:
        200: Character details
        401: Not authenticated
        404: Character not found or not owned by user
        500: Internal server error

    Example Response:
        {
            "result": {
                "character_id": "char_001",
                "name": "Thorin Ironheart",
                "class": {...},
                "origin": {...},
                "level": 5,
                "experience": 250,
                "base_stats": {...},
                "unlocked_skills": [...],
                "inventory": [...],
                "equipped": {...},
                "gold": 1000
            }
        }
    """
    try:
        user = get_current_user()
        logger.info("Getting character",
                   user_id=user.id,
                   character_id=character_id)

        # Get character service
        char_service = get_character_service()

        # Get character (ownership validated in service)
        character = char_service.get_character(character_id, user.id)

        logger.info("Character retrieved successfully",
                   user_id=user.id,
                   character_id=character_id)

        return success_response(result=character.to_dict())

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

    except Exception as e:
        logger.error("Failed to get character",
                    user_id=user.id,
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="CHARACTER_GET_ERROR",
            message="Failed to retrieve character",
            status=500
        )


@characters_bp.route('/api/v1/characters', methods=['POST'])
@require_auth
def create_character():
    """
    Create a new character for the current user.

    Request Body:
        {
            "name": "Thorin Ironheart",
            "class_id": "warrior",
            "origin_id": "soul_revenant"
        }

    Returns:
        201: Character created successfully
        400: Validation error or character limit exceeded
        401: Not authenticated
        500: Internal server error

    Example Response:
        {
            "result": {
                "character_id": "char_001",
                "name": "Thorin Ironheart",
                "class": "warrior",
                "level": 1,
                "message": "Character created successfully"
            }
        }
    """
    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"}
            )

        name = data.get('name', '').strip()
        class_id = data.get('class_id', '').strip().lower()
        origin_id = data.get('origin_id', '').strip().lower()

        # Validate inputs
        validation_errors = {}

        name_valid, name_error = validate_character_name(name)
        if not name_valid:
            validation_errors['name'] = name_error

        class_valid, class_error = validate_class_id(class_id)
        if not class_valid:
            validation_errors['class_id'] = class_error

        origin_valid, origin_error = validate_origin_id(origin_id)
        if not origin_valid:
            validation_errors['origin_id'] = origin_error

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

        logger.info("Creating character",
                   user_id=user.id,
                   name=name,
                   class_id=class_id,
                   origin_id=origin_id)

        # Get character service
        char_service = get_character_service()

        # Create character
        character = char_service.create_character(
            user_id=user.id,
            name=name,
            class_id=class_id,
            origin_id=origin_id
        )

        logger.info("Character created successfully",
                   user_id=user.id,
                   character_id=character.character_id,
                   name=name)

        return created_response(
            result={
                "character_id": character.character_id,
                "name": character.name,
                "class": character.player_class.class_id,
                "class_name": character.player_class.name,
                "origin": character.origin.id,
                "origin_name": character.origin.name,
                "level": character.level,
                "gold": character.gold,
                "current_location": character.current_location,
                "message": "Character created successfully"
            }
        )

    except CharacterLimitExceeded as e:
        logger.warning("Character limit exceeded",
                      user_id=user.id,
                      error=str(e))
        return error_response(
            code="CHARACTER_LIMIT_EXCEEDED",
            message=str(e),
            status=400
        )

    except ValueError as e:
        logger.warning("Invalid class or origin",
                      user_id=user.id,
                      error=str(e))
        return validation_error_response(
            message=str(e),
            details={"error": str(e)}
        )

    except Exception as e:
        logger.error("Failed to create character",
                    user_id=user.id,
                    error=str(e))
        return error_response(
            code="CHARACTER_CREATE_ERROR",
            message="Failed to create character",
            status=500
        )


@characters_bp.route('/api/v1/characters/<character_id>', methods=['DELETE'])
@require_auth
def delete_character(character_id: str):
    """
    Delete a character (soft delete - marks as inactive).

    Args:
        character_id: Character ID

    Returns:
        200: Character deleted successfully
        401: Not authenticated
        404: Character not found or not owned by user
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Character deleted successfully",
                "character_id": "char_001"
            }
        }
    """
    try:
        user = get_current_user()
        logger.info("Deleting character",
                   user_id=user.id,
                   character_id=character_id)

        # Get character service
        char_service = get_character_service()

        # Delete character (ownership validated in service)
        char_service.delete_character(character_id, user.id)

        logger.info("Character deleted successfully",
                   user_id=user.id,
                   character_id=character_id)

        return success_response(
            result={
                "message": "Character deleted successfully",
                "character_id": character_id
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for deletion",
                      user_id=user.id,
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except Exception as e:
        logger.error("Failed to delete character",
                    user_id=user.id,
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="CHARACTER_DELETE_ERROR",
            message="Failed to delete character",
            status=500
        )


@characters_bp.route('/api/v1/characters/<character_id>/skills/unlock', methods=['POST'])
@require_auth
def unlock_skill(character_id: str):
    """
    Unlock a skill for a character.

    Args:
        character_id: Character ID

    Request Body:
        {
            "skill_id": "power_strike"
        }

    Returns:
        200: Skill unlocked successfully
        400: Validation error or unlock requirements not met
        401: Not authenticated
        404: Character not found or not owned by user
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Skill unlocked successfully",
                "character_id": "char_001",
                "skill_id": "power_strike",
                "unlocked_skills": ["power_strike"],
                "available_points": 0
            }
        }
    """
    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"}
            )

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

        # Validate skill_id
        skill_valid, skill_error = validate_skill_id(skill_id)
        if not skill_valid:
            return validation_error_response(
                message="Validation failed",
                details={"skill_id": skill_error}
            )

        logger.info("Unlocking skill",
                   user_id=user.id,
                   character_id=character_id,
                   skill_id=skill_id)

        # Get character service
        char_service = get_character_service()

        # Unlock skill (validates ownership, prerequisites, skill points)
        character = char_service.unlock_skill(character_id, user.id, skill_id)

        # Calculate available skill points
        available_points = character.level - len(character.unlocked_skills)

        logger.info("Skill unlocked successfully",
                   user_id=user.id,
                   character_id=character_id,
                   skill_id=skill_id,
                   available_points=available_points)

        return success_response(
            result={
                "message": "Skill unlocked successfully",
                "character_id": character_id,
                "skill_id": skill_id,
                "unlocked_skills": character.unlocked_skills,
                "available_points": available_points
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for skill unlock",
                      user_id=user.id,
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except SkillUnlockError as e:
        logger.warning("Skill unlock failed",
                      user_id=user.id,
                      character_id=character_id,
                      skill_id=skill_id if 'skill_id' in locals() else 'unknown',
                      error=str(e))
        return error_response(
            code="SKILL_UNLOCK_ERROR",
            message=str(e),
            status=400
        )

    except Exception as e:
        logger.error("Failed to unlock skill",
                    user_id=user.id,
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="SKILL_UNLOCK_ERROR",
            message="Failed to unlock skill",
            status=500
        )


@characters_bp.route('/api/v1/characters/<character_id>/skills/respec', methods=['POST'])
@require_auth
def respec_skills(character_id: str):
    """
    Reset all unlocked skills for a character.

    Cost: level × 100 gold

    Args:
        character_id: Character ID

    Returns:
        200: Skills reset successfully
        400: Insufficient gold
        401: Not authenticated
        404: Character not found or not owned by user
        500: Internal server error

    Example Response:
        {
            "result": {
                "message": "Skills reset successfully",
                "character_id": "char_001",
                "cost": 500,
                "remaining_gold": 500,
                "available_points": 5
            }
        }
    """
    try:
        user = get_current_user()
        logger.info("Respecing character skills",
                   user_id=user.id,
                   character_id=character_id)

        # Get character service
        char_service = get_character_service()

        # Get character to calculate cost
        character = char_service.get_character(character_id, user.id)
        respec_cost = character.level * 100

        # Respec skills (validates ownership and gold)
        character = char_service.respec_skills(character_id, user.id)

        # Calculate available skill points
        available_points = character.level - len(character.unlocked_skills)

        logger.info("Skills respeced successfully",
                   user_id=user.id,
                   character_id=character_id,
                   cost=respec_cost,
                   remaining_gold=character.gold,
                   available_points=available_points)

        return success_response(
            result={
                "message": "Skills reset successfully",
                "character_id": character_id,
                "cost": respec_cost,
                "remaining_gold": character.gold,
                "available_points": available_points
            }
        )

    except CharacterNotFound as e:
        logger.warning("Character not found for respec",
                      user_id=user.id,
                      character_id=character_id,
                      error=str(e))
        return not_found_response(message=str(e))

    except InsufficientGold as e:
        logger.warning("Insufficient gold for respec",
                      user_id=user.id,
                      character_id=character_id,
                      error=str(e))
        return error_response(
            code="INSUFFICIENT_GOLD",
            message=str(e),
            status=400
        )

    except Exception as e:
        logger.error("Failed to respec skills",
                    user_id=user.id,
                    character_id=character_id,
                    error=str(e))
        return error_response(
            code="RESPEC_ERROR",
            message="Failed to reset skills",
            status=500
        )


# ===== CLASSES & ORIGINS ENDPOINTS (Reference Data) =====

@characters_bp.route('/api/v1/classes', methods=['GET'])
def list_classes():
    """
    List all available player classes.

    This endpoint provides reference data for character creation.
    No authentication required.

    Returns:
        200: List of all classes with basic info
        500: Internal server error

    Example Response:
        {
            "result": {
                "classes": [
                    {
                        "class_id": "vanguard",
                        "name": "Vanguard",
                        "description": "Armored warrior...",
                        "base_stats": {...},
                        "skill_trees": ["Shield Bearer", "Weapon Master"]
                    }
                ],
                "count": 8
            }
        }
    """
    try:
        logger.info("Listing all classes")

        # Get class loader
        class_loader = get_class_loader()

        # Get all class IDs
        class_ids = class_loader.get_all_class_ids()

        # Load all classes
        classes = []
        for class_id in class_ids:
            player_class = class_loader.load_class(class_id)
            if player_class:
                classes.append({
                    "class_id": player_class.class_id,
                    "name": player_class.name,
                    "description": player_class.description,
                    "base_stats": player_class.base_stats.to_dict(),
                    "skill_trees": [tree.name for tree in player_class.skill_trees],
                    "starting_equipment": player_class.starting_equipment,
                    "starting_abilities": player_class.starting_abilities
                })

        logger.info("Classes listed successfully", count=len(classes))

        return success_response(
            result={
                "classes": classes,
                "count": len(classes)
            }
        )

    except Exception as e:
        logger.error("Failed to list classes", error=str(e))
        return error_response(
            code="CLASS_LIST_ERROR",
            message="Failed to retrieve classes",
            status=500
        )


@characters_bp.route('/api/v1/classes/<class_id>', methods=['GET'])
def get_class(class_id: str):
    """
    Get detailed information about a specific class.

    This endpoint provides full class data including skill trees.
    No authentication required.

    Args:
        class_id: Class ID (e.g., "vanguard", "assassin")

    Returns:
        200: Full class details with skill trees
        404: Class not found
        500: Internal server error

    Example Response:
        {
            "result": {
                "class_id": "vanguard",
                "name": "Vanguard",
                "description": "Armored warrior...",
                "base_stats": {...},
                "skill_trees": [
                    {
                        "tree_id": "shield_bearer",
                        "name": "Shield Bearer",
                        "nodes": [...]
                    }
                ],
                "starting_equipment": [...],
                "starting_abilities": [...]
            }
        }
    """
    try:
        logger.info("Getting class details", class_id=class_id)

        # Get class loader
        class_loader = get_class_loader()

        # Load class
        player_class = class_loader.load_class(class_id)

        if not player_class:
            logger.warning("Class not found", class_id=class_id)
            return not_found_response(message=f"Class not found: {class_id}")

        logger.info("Class retrieved successfully", class_id=class_id)

        # Return full class data
        return success_response(result=player_class.to_dict())

    except Exception as e:
        logger.error("Failed to get class",
                    class_id=class_id,
                    error=str(e))
        return error_response(
            code="CLASS_GET_ERROR",
            message="Failed to retrieve class",
            status=500
        )


@characters_bp.route('/api/v1/origins', methods=['GET'])
def list_origins():
    """
    List all available character origins.

    This endpoint provides reference data for character creation.
    No authentication required.

    Returns:
        200: List of all origins
        500: Internal server error

    Example Response:
        {
            "result": {
                "origins": [
                    {
                        "id": "soul_revenant",
                        "name": "Soul Revenant",
                        "description": "Returned from death...",
                        "starting_location": {...},
                        "narrative_hooks": [...],
                        "starting_bonus": {...}
                    }
                ],
                "count": 4
            }
        }
    """
    try:
        logger.info("Listing all origins")

        # Get origin service
        origin_service = get_origin_service()

        # Get all origin IDs
        origin_ids = origin_service.get_all_origin_ids()

        # Load all origins
        origins = []
        for origin_id in origin_ids:
            origin = origin_service.load_origin(origin_id)
            if origin:
                origins.append(origin.to_dict())

        logger.info("Origins listed successfully", count=len(origins))

        return success_response(
            result={
                "origins": origins,
                "count": len(origins)
            }
        )

    except Exception as e:
        logger.error("Failed to list origins", error=str(e))
        return error_response(
            code="ORIGIN_LIST_ERROR",
            message="Failed to retrieve origins",
            status=500
        )
