"""
Character Views Blueprint

This module provides web UI routes for character management:
- Character creation flow (4 steps)
- Character list view
- Character detail view
- Skill tree view

All views require authentication and render HTML templates with HTMX.
"""

import time
from flask import Blueprint, render_template, request, session, redirect, url_for, flash
from app.utils.auth import require_auth_web, get_current_user
from app.utils.logging import get_logger
from app.utils.api_client import (
    get_api_client,
    APIError,
    APINotFoundError,
    APITimeoutError
)


# Initialize logger
logger = get_logger(__file__)

# Create blueprint
character_bp = Blueprint('character_views', __name__, url_prefix='/characters')

# Cache settings
_CACHE_TTL = 300  # 5 minutes in seconds
_origins_cache = {'data': None, 'timestamp': 0}
_classes_cache = {'data': None, 'timestamp': 0}

# Wizard session timeout (1 hour)
_WIZARD_TIMEOUT = 3600


def _get_cached_origins(api_client):
    """
    Get origins list with caching.

    Returns cached data if available and fresh, otherwise fetches from API.

    Args:
        api_client: API client instance.

    Returns:
        List of origin dictionaries.
    """
    global _origins_cache
    current_time = time.time()

    if _origins_cache['data'] and (current_time - _origins_cache['timestamp']) < _CACHE_TTL:
        logger.debug("Using cached origins")
        return _origins_cache['data']

    # Fetch from API
    response = api_client.get("/api/v1/origins")
    origins = response.get('result', {}).get('origins', [])

    # Update cache
    _origins_cache = {'data': origins, 'timestamp': current_time}
    logger.debug("Cached origins", count=len(origins))

    return origins


def _get_cached_classes(api_client):
    """
    Get classes list with caching.

    Returns cached data if available and fresh, otherwise fetches from API.

    Args:
        api_client: API client instance.

    Returns:
        List of class dictionaries.
    """
    global _classes_cache
    current_time = time.time()

    if _classes_cache['data'] and (current_time - _classes_cache['timestamp']) < _CACHE_TTL:
        logger.debug("Using cached classes")
        return _classes_cache['data']

    # Fetch from API
    response = api_client.get("/api/v1/classes")
    classes = response.get('result', {}).get('classes', [])

    # Update cache
    _classes_cache = {'data': classes, 'timestamp': current_time}
    logger.debug("Cached classes", count=len(classes))

    return classes


def _cleanup_stale_wizard_session():
    """
    Clean up stale character creation wizard session data.

    Called at the start of character creation to remove abandoned wizard data.
    """
    if 'character_creation' in session:
        creation_data = session['character_creation']
        started_at = creation_data.get('started_at', 0)
        current_time = time.time()

        if (current_time - started_at) > _WIZARD_TIMEOUT:
            logger.info("Cleaning up stale wizard session", age_seconds=int(current_time - started_at))
            session.pop('character_creation', None)


# ===== CHARACTER CREATION FLOW =====

@character_bp.route('/create/origin', methods=['GET', 'POST'])
@require_auth_web
def create_origin():
    """
    Step 1: Origin Selection

    GET: Display all available origins for user to choose from
    POST: Save selected origin to session and redirect to class selection
    """
    user = get_current_user()
    api_client = get_api_client()

    # Clean up any stale wizard session from previous attempts
    _cleanup_stale_wizard_session()

    logger.info("Character creation started - origin selection", user_id=user.get('id'))

    if request.method == 'POST':
        # Get selected origin from form
        origin_id = request.form.get('origin_id')

        if not origin_id:
            flash('Please select an origin story.', 'error')
            return redirect(url_for('character_views.create_origin'))

        # Validate origin exists using cached data
        try:
            origins = _get_cached_origins(api_client)

            # Check if selected origin_id is valid
            valid_origin = None
            for origin in origins:
                if origin.get('id') == origin_id:
                    valid_origin = origin
                    break

            if not valid_origin:
                flash('Invalid origin selected.', 'error')
                return redirect(url_for('character_views.create_origin'))

        except APIError as e:
            flash(f'Error validating origin: {e.message}', 'error')
            return redirect(url_for('character_views.create_origin'))

        # Store in session with timestamp
        session['character_creation'] = {
            'origin_id': origin_id,
            'step': 1,
            'started_at': time.time()
        }

        logger.info("Origin selected", user_id=user.get('id'), origin_id=origin_id)
        return redirect(url_for('character_views.create_class'))

    # GET: Display origin selection using cached data
    try:
        origins = _get_cached_origins(api_client)
    except APIError as e:
        logger.error("Failed to load origins", error=str(e))
        flash('Failed to load origins. Please try again.', 'error')
        origins = []

    return render_template(
        'character/create_origin.html',
        origins=origins,
        current_step=1
    )


@character_bp.route('/create/class', methods=['GET', 'POST'])
@require_auth_web
def create_class():
    """
    Step 2: Class Selection

    GET: Display all available classes for user to choose from
    POST: Save selected class to session and redirect to customization
    """
    user = get_current_user()
    api_client = get_api_client()

    # Ensure we have origin selected first
    if 'character_creation' not in session or session['character_creation'].get('step', 0) < 1:
        flash('Please start from the beginning.', 'warning')
        return redirect(url_for('character_views.create_origin'))

    if request.method == 'POST':
        # Get selected class from form
        class_id = request.form.get('class_id')

        if not class_id:
            flash('Please select a class.', 'error')
            return redirect(url_for('character_views.create_class'))

        # Validate class exists using cached data
        try:
            classes = _get_cached_classes(api_client)

            # Check if selected class_id is valid
            valid_class = None
            for player_class in classes:
                if player_class.get('class_id') == class_id:
                    valid_class = player_class
                    break

            if not valid_class:
                flash('Invalid class selected.', 'error')
                return redirect(url_for('character_views.create_class'))

        except APIError as e:
            flash(f'Error validating class: {e.message}', 'error')
            return redirect(url_for('character_views.create_class'))

        # Store in session
        session['character_creation']['class_id'] = class_id
        session['character_creation']['step'] = 2
        session.modified = True

        logger.info("Class selected", user_id=user.get('id'), class_id=class_id)
        return redirect(url_for('character_views.create_customize'))

    # GET: Display class selection using cached data
    try:
        classes = _get_cached_classes(api_client)
    except APIError as e:
        logger.error("Failed to load classes", error=str(e))
        flash('Failed to load classes. Please try again.', 'error')
        classes = []

    return render_template(
        'character/create_class.html',
        classes=classes,
        current_step=2
    )


@character_bp.route('/create/customize', methods=['GET', 'POST'])
@require_auth_web
def create_customize():
    """
    Step 3: Customize Character

    GET: Display form to enter character name
    POST: Save character name to session and redirect to confirmation
    """
    user = get_current_user()
    api_client = get_api_client()

    # Ensure we have both origin and class selected
    if 'character_creation' not in session or session['character_creation'].get('step', 0) < 2:
        flash('Please complete previous steps first.', 'warning')
        return redirect(url_for('character_views.create_origin'))

    if request.method == 'POST':
        # Get character name from form
        character_name = request.form.get('name', '').strip()

        if not character_name:
            flash('Please enter a character name.', 'error')
            return redirect(url_for('character_views.create_customize'))

        # Validate name length (3-30 characters)
        if len(character_name) < 3 or len(character_name) > 30:
            flash('Character name must be between 3 and 30 characters.', 'error')
            return redirect(url_for('character_views.create_customize'))

        # Store in session
        session['character_creation']['name'] = character_name
        session['character_creation']['step'] = 3
        session.modified = True

        logger.info("Character name entered", user_id=user.get('id'), name=character_name)
        return redirect(url_for('character_views.create_confirm'))

    # GET: Display customization form
    creation_data = session.get('character_creation', {})

    # Load origin and class for display using cached data
    origin = None
    player_class = None

    try:
        # Find origin in cached list
        if creation_data.get('origin_id'):
            origins = _get_cached_origins(api_client)
            for o in origins:
                if o.get('id') == creation_data['origin_id']:
                    origin = o
                    break

        # Fetch class - can use single endpoint
        if creation_data.get('class_id'):
            response = api_client.get(f"/api/v1/classes/{creation_data['class_id']}")
            player_class = response.get('result')

    except APIError as e:
        logger.error("Failed to load origin/class data", error=str(e))

    return render_template(
        'character/create_customize.html',
        origin=origin,
        player_class=player_class,
        current_step=3
    )


@character_bp.route('/create/confirm', methods=['GET', 'POST'])
@require_auth_web
def create_confirm():
    """
    Step 4: Confirm and Create Character

    GET: Display character summary for final confirmation
    POST: Create the character via API and redirect to character list
    """
    user = get_current_user()
    api_client = get_api_client()

    # Ensure we have all data
    if 'character_creation' not in session or session['character_creation'].get('step', 0) < 3:
        flash('Please complete all steps first.', 'warning')
        return redirect(url_for('character_views.create_origin'))

    creation_data = session.get('character_creation', {})

    if request.method == 'POST':
        # Create the character via API
        try:
            response = api_client.post("/api/v1/characters", data={
                'name': creation_data['name'],
                'class_id': creation_data['class_id'],
                'origin_id': creation_data['origin_id']
            })

            character = response.get('result', {})

            # Clear session data
            session.pop('character_creation', None)

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

            flash(f'Character "{character.get("name")}" created successfully!', 'success')
            return redirect(url_for('character_views.list_characters'))

        except APIError as e:
            if 'limit' in e.message.lower():
                logger.warning("Character limit exceeded", user_id=user.get('id'), error=str(e))
                flash(e.message, 'error')
                return redirect(url_for('character_views.list_characters'))

            logger.error(
                "Failed to create character",
                user_id=user.get('id'),
                error=str(e)
            )
            flash('An error occurred while creating your character. Please try again.', 'error')
            return redirect(url_for('character_views.create_origin'))

    # GET: Display confirmation page using cached data
    origin = None
    player_class = None

    try:
        # Find origin in cached list
        origins = _get_cached_origins(api_client)
        for o in origins:
            if o.get('id') == creation_data['origin_id']:
                origin = o
                break

        # Fetch class - can use single endpoint
        response = api_client.get(f"/api/v1/classes/{creation_data['class_id']}")
        player_class = response.get('result')

    except APIError as e:
        logger.error("Failed to load origin/class data", error=str(e))

    return render_template(
        'character/create_confirm.html',
        character_name=creation_data['name'],
        origin=origin,
        player_class=player_class,
        current_step=4
    )


# ===== CHARACTER MANAGEMENT =====

@character_bp.route('/')
@require_auth_web
def list_characters():
    """
    Display list of all characters for the current user.

    Also fetches active sessions and maps them to characters.
    """
    user = get_current_user()
    api_client = get_api_client()

    try:
        response = api_client.get("/api/v1/characters")
        result = response.get('result', {})

        # API returns characters in nested structure
        characters = result.get('characters', [])
        api_tier = result.get('tier', 'free')
        api_limit = result.get('limit', 1)

        current_tier = api_tier
        max_characters = api_limit
        can_create = len(characters) < max_characters

        # Fetch all user sessions and map to characters
        sessions_by_character = {}
        try:
            sessions_response = api_client.get("/api/v1/sessions")
            sessions = sessions_response.get('result', [])
            # Handle case where result is a list or a dict with sessions key
            if isinstance(sessions, dict):
                sessions = sessions.get('sessions', [])

            for sess in sessions:
                char_id = sess.get('character_id')
                if char_id:
                    if char_id not in sessions_by_character:
                        sessions_by_character[char_id] = []
                    sessions_by_character[char_id].append(sess)
        except (APIError, APINotFoundError) as e:
            # Sessions endpoint may not exist or have issues
            logger.debug("Could not fetch sessions", error=str(e))

        # Attach sessions to each character
        for character in characters:
            char_id = character.get('character_id')
            character['sessions'] = sessions_by_character.get(char_id, [])

        logger.info(
            "Characters listed",
            user_id=user.get('id'),
            count=len(characters),
            tier=current_tier
        )

        return render_template(
            'character/list.html',
            characters=characters,
            current_tier=current_tier,
            max_characters=max_characters,
            can_create=can_create
        )

    except APITimeoutError:
        logger.error("API timeout while listing characters", user_id=user.get('id'))
        flash('Request timed out. Please try again.', 'error')
        return render_template('character/list.html', characters=[], can_create=False)

    except APIError as e:
        logger.error("Failed to list characters", user_id=user.get('id'), error=str(e))
        flash('An error occurred while loading your characters.', 'error')
        return render_template('character/list.html', characters=[], can_create=False)


@character_bp.route('/<character_id>')
@require_auth_web
def view_character(character_id: str):
    """
    Display detailed view of a specific character.

    Args:
        character_id: ID of the character to view
    """
    user = get_current_user()
    api_client = get_api_client()

    try:
        response = api_client.get(f"/api/v1/characters/{character_id}")
        character = response.get('result')

        logger.info(
            "Character viewed",
            user_id=user.get('id'),
            character_id=character_id
        )

        return render_template('character/detail.html', character=character)

    except APINotFoundError:
        logger.warning("Character not found", user_id=user.get('id'), character_id=character_id)
        flash('Character not found.', 'error')
        return redirect(url_for('character_views.list_characters'))

    except APIError as e:
        logger.error(
            "Failed to view character",
            user_id=user.get('id'),
            character_id=character_id,
            error=str(e)
        )
        flash('An error occurred while loading the character.', 'error')
        return redirect(url_for('character_views.list_characters'))


@character_bp.route('/<character_id>/delete', methods=['POST'])
@require_auth_web
def delete_character(character_id: str):
    """
    Delete a character (soft delete - marks as inactive).

    Args:
        character_id: ID of the character to delete
    """
    user = get_current_user()
    api_client = get_api_client()

    try:
        api_client.delete(f"/api/v1/characters/{character_id}")

        logger.info("Character deleted", user_id=user.get('id'), character_id=character_id)
        flash('Character deleted successfully.', 'success')

    except APINotFoundError:
        logger.warning("Character not found for deletion", user_id=user.get('id'), character_id=character_id)
        flash('Character not found.', 'error')

    except APIError as e:
        logger.error(
            "Failed to delete character",
            user_id=user.get('id'),
            character_id=character_id,
            error=str(e)
        )
        flash('An error occurred while deleting the character.', 'error')

    return redirect(url_for('character_views.list_characters'))


# ===== SESSION MANAGEMENT =====

@character_bp.route('/<character_id>/play', methods=['POST'])
@require_auth_web
def create_session(character_id: str):
    """
    Create a new game session for a character and redirect to play screen.

    Args:
        character_id: ID of the character to start a session with
    """
    user = get_current_user()
    api_client = get_api_client()

    try:
        # Create new session via API
        response = api_client.post("/api/v1/sessions", data={
            'character_id': character_id
        })

        result = response.get('result', {})
        session_id = result.get('session_id')

        if not session_id:
            flash('Failed to create session - no session ID returned.', 'error')
            return redirect(url_for('character_views.list_characters'))

        logger.info(
            "Session created",
            user_id=user.get('id'),
            character_id=character_id,
            session_id=session_id
        )

        # Redirect to play screen
        return redirect(url_for('game.play_session', session_id=session_id))

    except APINotFoundError:
        logger.warning("Character not found for session creation", user_id=user.get('id'), character_id=character_id)
        flash('Character not found.', 'error')
        return redirect(url_for('character_views.list_characters'))

    except APIError as e:
        logger.error(
            "Failed to create session",
            user_id=user.get('id'),
            character_id=character_id,
            error=str(e)
        )
        # Check for specific errors (session limit, etc.)
        if 'limit' in str(e).lower():
            flash(f'Session limit reached: {e.message}', 'error')
        else:
            flash(f'Failed to create session: {e.message}', 'error')
        return redirect(url_for('character_views.list_characters'))


@character_bp.route('/<character_id>/skills')
@require_auth_web
def view_skills(character_id: str):
    """
    Display skill tree view for a specific character.

    Args:
        character_id: ID of the character to view skills for
    """
    user = get_current_user()
    api_client = get_api_client()

    try:
        # Get character data
        response = api_client.get(f"/api/v1/characters/{character_id}")
        character = response.get('result')

        # Load class data to get skill trees
        class_id = character.get('class_id')
        player_class = None

        if class_id:
            response = api_client.get(f"/api/v1/classes/{class_id}")
            player_class = response.get('result')

        logger.info(
            "Skill tree viewed",
            user_id=user.get('id'),
            character_id=character_id
        )

        return render_template(
            'character/skills.html',
            character=character,
            player_class=player_class
        )

    except APINotFoundError:
        logger.warning("Character not found for skills view", user_id=user.get('id'), character_id=character_id)
        flash('Character not found.', 'error')
        return redirect(url_for('character_views.list_characters'))

    except APIError as e:
        logger.error(
            "Failed to view skills",
            user_id=user.get('id'),
            character_id=character_id,
            error=str(e)
        )
        flash('An error occurred while loading the skill tree.', 'error')
        return redirect(url_for('character_views.list_characters'))
