"""
Travel API Blueprint

This module provides API endpoints for location-based travel:
- Get available destinations
- Travel to a location
- Get current location details

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

from flask import Blueprint, request

from app.services.session_service import get_session_service, SessionNotFound
from app.services.character_service import get_character_service, CharacterNotFound
from app.services.location_loader import get_location_loader
from app.services.npc_loader import get_npc_loader
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
travel_bp = Blueprint('travel', __name__)


@travel_bp.route('/api/v1/travel/available', methods=['GET'])
@require_auth
def get_available_destinations():
    """
    Get all locations the character can travel to.

    Query params:
        session_id: Active session ID

    Returns:
        JSON response with list of available destinations
    """
    try:
        user = get_current_user()
        session_id = request.args.get('session_id')

        if not session_id:
            return validation_error_response("session_id query parameter is required")

        # Get session and verify ownership
        session_service = get_session_service()
        session = session_service.get_session(session_id, user.id)

        # Get character for discovered locations
        character_service = get_character_service()
        character = character_service.get_character(session.solo_character_id, user.id)

        # Load location details for each discovered location
        location_loader = get_location_loader()
        destinations = []

        for loc_id in character.discovered_locations:
            # Skip current location
            if loc_id == session.game_state.current_location:
                continue

            location = location_loader.load_location(loc_id)
            if location:
                destinations.append({
                    "location_id": location.location_id,
                    "name": location.name,
                    "location_type": location.location_type.value,
                    "region_id": location.region_id,
                    "description": location.description[:200] + "..." if len(location.description) > 200 else location.description,
                })

        logger.info("Retrieved available destinations",
                   user_id=user.id,
                   session_id=session_id,
                   destination_count=len(destinations))

        return success_response({
            "current_location": session.game_state.current_location,
            "destinations": destinations
        })

    except SessionNotFound:
        return not_found_response("Session not found")
    except CharacterNotFound:
        return not_found_response("Character not found")
    except Exception as e:
        logger.error("Failed to get available destinations",
                    error=str(e))
        return error_response("Failed to get destinations", 500)


@travel_bp.route('/api/v1/travel', methods=['POST'])
@require_auth
def travel_to_location():
    """
    Travel to a discovered location.

    Request body:
        session_id: Active session ID
        location_id: Target location ID

    Returns:
        JSON response with new location details and NPCs present
    """
    try:
        user = get_current_user()
        data = request.get_json()

        session_id = data.get('session_id')
        location_id = data.get('location_id')

        # Validate required fields
        if not session_id:
            return validation_error_response("session_id is required")
        if not location_id:
            return validation_error_response("location_id is required")

        # Get session and verify ownership
        session_service = get_session_service()
        session = session_service.get_session(session_id, user.id)

        # Get character and verify location is discovered
        character_service = get_character_service()
        character = character_service.get_character(session.solo_character_id, user.id)

        if location_id not in character.discovered_locations:
            logger.warning("Attempted travel to undiscovered location",
                          user_id=user.id,
                          character_id=character.character_id,
                          location_id=location_id)
            return error_response("Location not discovered", 403)

        # Load location details
        location_loader = get_location_loader()
        location = location_loader.load_location(location_id)

        if not location:
            logger.error("Location not found in data files",
                        location_id=location_id)
            return not_found_response("Location not found")

        # Update session with new location
        session = session_service.update_location(
            session_id,
            location_id,
            location.location_type
        )

        # Get NPCs at new location
        npc_loader = get_npc_loader()
        npcs = npc_loader.get_npcs_at_location(location_id)

        # Build NPC summary list
        npcs_present = []
        for npc in npcs:
            npcs_present.append({
                "npc_id": npc.npc_id,
                "name": npc.name,
                "role": npc.role,
                "appearance": npc.appearance.brief,
            })

        logger.info("Character traveled to location",
                   user_id=user.id,
                   session_id=session_id,
                   location_id=location_id)

        return success_response({
            "location": location.to_dict(),
            "npcs_present": npcs_present,
            "game_state": session.game_state.to_dict(),
        })

    except SessionNotFound:
        return not_found_response("Session not found")
    except CharacterNotFound:
        return not_found_response("Character not found")
    except Exception as e:
        logger.error("Failed to travel to location",
                    error=str(e))
        return error_response("Failed to travel", 500)


@travel_bp.route('/api/v1/travel/location/<location_id>', methods=['GET'])
@require_auth
def get_location_details(location_id: str):
    """
    Get details about a specific location.

    Path params:
        location_id: Location ID to get details for

    Query params:
        session_id: Active session ID (optional, for context)

    Returns:
        JSON response with location details and NPCs
    """
    try:
        user = get_current_user()

        # Load location
        location_loader = get_location_loader()
        location = location_loader.load_location(location_id)

        if not location:
            return not_found_response("Location not found")

        # Get NPCs at location
        npc_loader = get_npc_loader()
        npcs = npc_loader.get_npcs_at_location(location_id)

        npcs_present = []
        for npc in npcs:
            npcs_present.append({
                "npc_id": npc.npc_id,
                "name": npc.name,
                "role": npc.role,
                "appearance": npc.appearance.brief,
            })

        return success_response({
            "location": location.to_dict(),
            "npcs_present": npcs_present,
        })

    except Exception as e:
        logger.error("Failed to get location details",
                    location_id=location_id,
                    error=str(e))
        return error_response("Failed to get location", 500)


@travel_bp.route('/api/v1/travel/current', methods=['GET'])
@require_auth
def get_current_location():
    """
    Get details about the current location in a session.

    Query params:
        session_id: Active session ID

    Returns:
        JSON response with current location details and NPCs
    """
    try:
        user = get_current_user()
        session_id = request.args.get('session_id')

        if not session_id:
            return validation_error_response("session_id query parameter is required")

        # Get session
        session_service = get_session_service()
        session = session_service.get_session(session_id, user.id)

        current_location_id = session.game_state.current_location

        # Load location
        location_loader = get_location_loader()
        location = location_loader.load_location(current_location_id)

        if not location:
            # Location not in data files - return basic info from session
            return success_response({
                "location": {
                    "location_id": current_location_id,
                    "name": current_location_id,
                    "location_type": session.game_state.location_type.value,
                },
                "npcs_present": [],
            })

        # Get NPCs at location
        npc_loader = get_npc_loader()
        npcs = npc_loader.get_npcs_at_location(current_location_id)

        npcs_present = []
        for npc in npcs:
            npcs_present.append({
                "npc_id": npc.npc_id,
                "name": npc.name,
                "role": npc.role,
                "appearance": npc.appearance.brief,
            })

        return success_response({
            "location": location.to_dict(),
            "npcs_present": npcs_present,
        })

    except SessionNotFound:
        return not_found_response("Session not found")
    except Exception as e:
        logger.error("Failed to get current location",
                    error=str(e))
        return error_response("Failed to get current location", 500)
