"""
NPC API Blueprint

This module provides API endpoints for NPC interactions:
- Get NPC details
- Talk to NPC (queues AI dialogue generation)
- Get NPCs at location

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

from datetime import datetime, timezone
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.npc_loader import get_npc_loader
from app.services.location_loader import get_location_loader
from app.tasks.ai_tasks import enqueue_ai_task, TaskType
from app.utils.response import (
    success_response,
    accepted_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
npcs_bp = Blueprint('npcs', __name__)


@npcs_bp.route('/api/v1/npcs/<npc_id>', methods=['GET'])
@require_auth
def get_npc_details(npc_id: str):
    """
    Get NPC details with knowledge filtered by character interaction state.

    Path params:
        npc_id: NPC ID to get details for

    Query params:
        character_id: Optional character ID for filtering revealed secrets

    Returns:
        JSON response with NPC details
    """
    try:
        user = get_current_user()
        character_id = request.args.get('character_id')

        # Load NPC
        npc_loader = get_npc_loader()
        npc = npc_loader.load_npc(npc_id)

        if not npc:
            return not_found_response("NPC not found")

        npc_data = npc.to_dict()

        # Filter knowledge based on character interaction state
        if character_id:
            try:
                character_service = get_character_service()
                character = character_service.get_character(character_id, user.id)

                if character:
                    # Get revealed secrets based on conditions
                    revealed = character_service.check_npc_secret_conditions(character, npc)

                    # Build available knowledge (public + revealed)
                    available_knowledge = []
                    if npc.knowledge:
                        available_knowledge.extend(npc.knowledge.public)
                        available_knowledge.extend(revealed)

                    npc_data["available_knowledge"] = available_knowledge

                    # Remove secret knowledge from response
                    if npc_data.get("knowledge"):
                        npc_data["knowledge"]["secret"] = []
                        npc_data["knowledge"]["will_share_if"] = []

                    # Add interaction summary
                    interaction = character.npc_interactions.get(npc_id, {})
                    npc_data["interaction_summary"] = {
                        "interaction_count": interaction.get("interaction_count", 0),
                        "relationship_level": interaction.get("relationship_level", 50),
                        "first_met": interaction.get("first_met"),
                    }

            except CharacterNotFound:
                logger.debug("Character not found for NPC filter", character_id=character_id)

        return success_response(npc_data)

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


@npcs_bp.route('/api/v1/npcs/<npc_id>/talk', methods=['POST'])
@require_auth
def talk_to_npc(npc_id: str):
    """
    Initiate conversation with an NPC.

    Validates NPC is at current location, updates interaction state,
    and queues AI dialogue generation task.

    Path params:
        npc_id: NPC ID to talk to

    Request body:
        session_id: Active session ID
        topic: Conversation topic/opener (default: "greeting")
        player_response: What the player says to the NPC (overrides topic if provided)

    Returns:
        JSON response with job_id for polling result
    """
    try:
        user = get_current_user()
        data = request.get_json()

        session_id = data.get('session_id')
        # player_response overrides topic for bidirectional dialogue
        player_response = data.get('player_response')
        topic = player_response if player_response else data.get('topic', 'greeting')

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

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

        # Load NPC
        npc_loader = get_npc_loader()
        npc = npc_loader.load_npc(npc_id)

        if not npc:
            return not_found_response("NPC not found")

        # Validate NPC is at current location
        if npc.location_id != session.game_state.current_location:
            logger.warning("NPC not at current location",
                          npc_id=npc_id,
                          npc_location=npc.location_id,
                          current_location=session.game_state.current_location)
            return error_response("NPC is not at your current location", 400)

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

        # Get or create interaction state
        now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
        interaction = character.npc_interactions.get(npc_id, {})

        if not interaction:
            # First meeting
            interaction = {
                "npc_id": npc_id,
                "first_met": now,
                "last_interaction": now,
                "interaction_count": 1,
                "revealed_secrets": [],
                "relationship_level": 50,
                "custom_flags": {},
            }
        else:
            # Update existing interaction
            interaction["last_interaction"] = now
            interaction["interaction_count"] = interaction.get("interaction_count", 0) + 1

        # Check for newly revealed secrets
        revealed = character_service.check_npc_secret_conditions(character, npc)

        # Update character with new interaction state
        character_service.update_npc_interaction(
            character.character_id,
            user.id,
            npc_id,
            interaction
        )

        # Build NPC knowledge for AI context
        npc_knowledge = []
        if npc.knowledge:
            npc_knowledge.extend(npc.knowledge.public)
            npc_knowledge.extend(revealed)

        # Get previous dialogue history for context (last 3 exchanges)
        previous_dialogue = character_service.get_npc_dialogue_history(
            character.character_id,
            user.id,
            npc_id,
            limit=3
        )

        # Prepare AI context
        task_context = {
            "session_id": session_id,
            "character_id": character.character_id,
            "character": character.to_story_dict(),
            "npc": npc.to_story_dict(),
            "npc_full": npc.to_dict(),  # Full NPC data for reference
            "conversation_topic": topic,
            "game_state": session.game_state.to_dict(),
            "npc_knowledge": npc_knowledge,
            "revealed_secrets": revealed,
            "interaction_count": interaction["interaction_count"],
            "relationship_level": interaction.get("relationship_level", 50),
            "previous_dialogue": previous_dialogue,  # Pass conversation history
        }

        # Enqueue AI task
        result = enqueue_ai_task(
            task_type=TaskType.NPC_DIALOGUE,
            user_id=user.id,
            context=task_context,
            priority="normal",
            session_id=session_id,
            character_id=character.character_id
        )

        logger.info("NPC dialogue task queued",
                   user_id=user.id,
                   npc_id=npc_id,
                   job_id=result.get('job_id'),
                   interaction_count=interaction["interaction_count"])

        return accepted_response({
            "job_id": result.get('job_id'),
            "status": "queued",
            "message": f"Starting conversation with {npc.name}...",
            "npc_name": npc.name,
            "npc_role": npc.role,
        })

    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 talk to NPC",
                    npc_id=npc_id,
                    error=str(e))
        return error_response("Failed to start conversation", 500)


@npcs_bp.route('/api/v1/npcs/at-location/<location_id>', methods=['GET'])
@require_auth
def get_npcs_at_location(location_id: str):
    """
    Get all NPCs at a specific location.

    Path params:
        location_id: Location ID to get NPCs for

    Returns:
        JSON response with list of NPCs at location
    """
    try:
        npc_loader = get_npc_loader()
        npcs = npc_loader.get_npcs_at_location(location_id)

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

        return success_response({
            "location_id": location_id,
            "npcs": npcs_list,
        })

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


@npcs_bp.route('/api/v1/npcs/<npc_id>/relationship', methods=['POST'])
@require_auth
def adjust_npc_relationship(npc_id: str):
    """
    Adjust relationship level with an NPC.

    Path params:
        npc_id: NPC ID

    Request body:
        character_id: Character ID
        adjustment: Amount to add/subtract (can be negative)

    Returns:
        JSON response with updated relationship level
    """
    try:
        user = get_current_user()
        data = request.get_json()

        character_id = data.get('character_id')
        adjustment = data.get('adjustment', 0)

        if not character_id:
            return validation_error_response("character_id is required")

        if not isinstance(adjustment, int):
            return validation_error_response("adjustment must be an integer")

        # Validate NPC exists
        npc_loader = get_npc_loader()
        npc = npc_loader.load_npc(npc_id)

        if not npc:
            return not_found_response("NPC not found")

        # Adjust relationship
        character_service = get_character_service()
        character = character_service.adjust_npc_relationship(
            character_id,
            user.id,
            npc_id,
            adjustment
        )

        new_level = character.npc_interactions.get(npc_id, {}).get("relationship_level", 50)

        logger.info("NPC relationship adjusted",
                   npc_id=npc_id,
                   character_id=character_id,
                   adjustment=adjustment,
                   new_level=new_level)

        return success_response({
            "npc_id": npc_id,
            "relationship_level": new_level,
        })

    except CharacterNotFound:
        return not_found_response("Character not found")
    except Exception as e:
        logger.error("Failed to adjust NPC relationship",
                    npc_id=npc_id,
                    error=str(e))
        return error_response("Failed to adjust relationship", 500)


@npcs_bp.route('/api/v1/npcs/<npc_id>/flag', methods=['POST'])
@require_auth
def set_npc_flag(npc_id: str):
    """
    Set a custom flag on NPC interaction (e.g., "helped_with_rats": true).

    Path params:
        npc_id: NPC ID

    Request body:
        character_id: Character ID
        flag_name: Name of the flag
        flag_value: Value to set

    Returns:
        JSON response confirming flag was set
    """
    try:
        user = get_current_user()
        data = request.get_json()

        character_id = data.get('character_id')
        flag_name = data.get('flag_name')
        flag_value = data.get('flag_value')

        if not character_id:
            return validation_error_response("character_id is required")
        if not flag_name:
            return validation_error_response("flag_name is required")

        # Validate NPC exists
        npc_loader = get_npc_loader()
        npc = npc_loader.load_npc(npc_id)

        if not npc:
            return not_found_response("NPC not found")

        # Set flag
        character_service = get_character_service()
        character_service.set_npc_custom_flag(
            character_id,
            user.id,
            npc_id,
            flag_name,
            flag_value
        )

        logger.info("NPC flag set",
                   npc_id=npc_id,
                   character_id=character_id,
                   flag_name=flag_name)

        return success_response({
            "npc_id": npc_id,
            "flag_name": flag_name,
            "flag_value": flag_value,
        })

    except CharacterNotFound:
        return not_found_response("Character not found")
    except Exception as e:
        logger.error("Failed to set NPC flag",
                    npc_id=npc_id,
                    error=str(e))
        return error_response("Failed to set flag", 500)
