"""
Combat Views

Routes for combat UI.
"""

from flask import Blueprint, render_template, request, redirect, url_for, make_response
import structlog

from ..utils.api_client import get_api_client, APIError, APINotFoundError
from ..utils.auth import require_auth_web as require_auth

logger = structlog.get_logger(__name__)

combat_bp = Blueprint('combat', __name__, url_prefix='/combat')


@combat_bp.route('/<session_id>')
@require_auth
def combat_view(session_id: str):
    """
    Render the combat page for an active encounter.

    Displays the 3-column combat interface with:
    - Left: Combatants (player + enemies) with HP/MP bars
    - Center: Combat log + action buttons
    - Right: Turn order + active effects
    """
    client = get_api_client()

    try:
        # Get combat state from API
        response = client.get(f'/api/v1/combat/{session_id}/state')
        result = response.get('result', {})

        # Check if combat is still active
        if not result.get('in_combat'):
            # Combat ended - redirect to game play
            return redirect(url_for('game.play_session', session_id=session_id))

        encounter = result.get('encounter') or {}
        combat_log = result.get('combat_log', [])

        # Get current turn combatant ID directly from API response
        current_turn_id = encounter.get('current_turn')

        # Find if it's the player's turn
        is_player_turn = False
        player_combatant = None
        for combatant in encounter.get('combatants', []):
            if combatant.get('is_player'):
                player_combatant = combatant
                if combatant.get('combatant_id') == current_turn_id:
                    is_player_turn = True
                break

        # Format combat log entries for display
        formatted_log = []
        for entry in combat_log:
            log_entry = {
                'actor': entry.get('combatant_name', entry.get('actor', '')),
                'message': entry.get('message', ''),
                'damage': entry.get('damage'),
                'heal': entry.get('healing'),
                'is_crit': entry.get('is_critical', False),
                'type': 'player' if entry.get('is_player', False) else 'enemy'
            }
            # Detect system messages
            if entry.get('action_type') in ('round_start', 'combat_start', 'combat_end'):
                log_entry['type'] = 'system'
            formatted_log.append(log_entry)

        return render_template(
            'game/combat.html',
            session_id=session_id,
            encounter=encounter,
            combat_log=formatted_log,
            current_turn_id=current_turn_id,
            is_player_turn=is_player_turn,
            player_combatant=player_combatant
        )

    except APINotFoundError:
        logger.warning("combat_not_found", session_id=session_id)
        return render_template('errors/404.html', message="No active combat encounter"), 404
    except APIError as e:
        logger.error("failed_to_load_combat", session_id=session_id, error=str(e))
        return render_template('errors/500.html', message=str(e)), 500


@combat_bp.route('/<session_id>/action', methods=['POST'])
@require_auth
def combat_action(session_id: str):
    """
    Execute a combat action (attack, defend, ability, item).

    Returns updated combat log entries.
    """
    client = get_api_client()

    action_type = request.form.get('action_type', 'attack')
    ability_id = request.form.get('ability_id')
    item_id = request.form.get('item_id')
    target_id = request.form.get('target_id')

    try:
        # Build action payload
        payload = {
            'action_type': action_type
        }

        if ability_id:
            payload['ability_id'] = ability_id
        if item_id:
            payload['item_id'] = item_id
        if target_id:
            payload['target_id'] = target_id

        # POST action to API
        response = client.post(f'/api/v1/combat/{session_id}/action', payload)
        result = response.get('result', {})

        # Check if combat ended
        combat_ended = result.get('combat_ended', False)
        combat_status = result.get('combat_status')

        if combat_ended:
            # API returns lowercase status values: 'victory', 'defeat', 'fled'
            status_lower = (combat_status or '').lower()
            if status_lower == 'victory':
                return render_template(
                    'game/partials/combat_victory.html',
                    session_id=session_id,
                    rewards=result.get('rewards', {})
                )
            elif status_lower == 'defeat':
                return render_template(
                    'game/partials/combat_defeat.html',
                    session_id=session_id,
                    gold_lost=result.get('gold_lost', 0),
                    can_retry=result.get('can_retry', False)
                )

        # Format action result for log display
        # API returns data directly in result, not nested under 'action_result'
        log_entries = []

        # Player action entry
        player_entry = {
            'actor': 'You',
            'message': result.get('message', f'used {action_type}'),
            'type': 'player',
            'is_crit': False
        }

        # Add damage info if present
        damage_results = result.get('damage_results', [])
        if damage_results:
            for dmg in damage_results:
                player_entry['damage'] = dmg.get('total_damage') or dmg.get('damage')
                player_entry['is_crit'] = dmg.get('is_critical', False)
                if player_entry['is_crit']:
                    player_entry['type'] = 'crit'

        # Add healing info if present
        if result.get('healing'):
            player_entry['heal'] = result.get('healing')
            player_entry['type'] = 'heal'

        log_entries.append(player_entry)

        # Add any effect entries
        for effect in result.get('effects_applied', []):
            # API may use "name" or "effect" key for the effect name
            effect_name = effect.get('name') or effect.get('effect') or 'Unknown'
            log_entries.append({
                'actor': '',
                'message': effect.get('message', f'Effect applied: {effect_name}'),
                'type': 'system'
            })

        # Return log entries HTML
        resp = make_response(render_template(
            'game/partials/combat_log.html',
            combat_log=log_entries
        ))

        # Trigger enemy turn if it's no longer player's turn
        next_combatant = result.get('next_combatant_id')
        if next_combatant and not result.get('next_is_player', True):
            resp.headers['HX-Trigger'] = 'enemyTurn'

        return resp

    except APIError as e:
        logger.error("combat_action_failed", session_id=session_id, action_type=action_type, error=str(e))
        return f'''
        <div class="combat-log__entry combat-log__entry--system">
            <span class="log-message">Action failed: {e}</span>
        </div>
        ''', 500


@combat_bp.route('/<session_id>/abilities')
@require_auth
def combat_abilities(session_id: str):
    """Get abilities modal for combat."""
    client = get_api_client()

    try:
        # Get combat state to get player's abilities
        response = client.get(f'/api/v1/combat/{session_id}/state')
        result = response.get('result', {})
        encounter = result.get('encounter', {})

        # Find player combatant
        player_combatant = None
        for combatant in encounter.get('combatants', []):
            if combatant.get('is_player'):
                player_combatant = combatant
                break

        # Get abilities from player combatant or character
        abilities = []
        if player_combatant:
            ability_ids = player_combatant.get('abilities', [])
            current_mp = player_combatant.get('current_mp', 0)
            cooldowns = player_combatant.get('cooldowns', {})

            # Fetch ability details (if API has ability endpoint)
            for ability_id in ability_ids:
                try:
                    ability_response = client.get(f'/api/v1/abilities/{ability_id}')
                    ability_data = ability_response.get('result', {})

                    # Check availability
                    mp_cost = ability_data.get('mp_cost', 0)
                    cooldown = cooldowns.get(ability_id, 0)
                    available = current_mp >= mp_cost and cooldown == 0

                    abilities.append({
                        'id': ability_id,
                        'name': ability_data.get('name', ability_id),
                        'description': ability_data.get('description', ''),
                        'mp_cost': mp_cost,
                        'cooldown': cooldown,
                        'max_cooldown': ability_data.get('cooldown', 0),
                        'damage_type': ability_data.get('damage_type'),
                        'effect_type': ability_data.get('effect_type'),
                        'available': available
                    })
                except (APINotFoundError, APIError):
                    # Ability not found, add basic entry
                    abilities.append({
                        'id': ability_id,
                        'name': ability_id.replace('_', ' ').title(),
                        'description': '',
                        'mp_cost': 0,
                        'cooldown': cooldowns.get(ability_id, 0),
                        'max_cooldown': 0,
                        'available': True
                    })

        return render_template(
            'game/partials/ability_modal.html',
            session_id=session_id,
            abilities=abilities
        )

    except APIError as e:
        logger.error("failed_to_load_abilities", session_id=session_id, error=str(e))
        return f'''
        <div class="modal-overlay" onclick="closeModal()">
            <div class="modal-content modal-content--md">
                <div class="modal-header">
                    <h3 class="modal-title">Select Ability</h3>
                    <button class="modal-close" onclick="closeModal()">&times;</button>
                </div>
                <div class="modal-body">
                    <div class="items-empty">Failed to load abilities: {e}</div>
                </div>
            </div>
        </div>
        '''


@combat_bp.route('/<session_id>/items')
@require_auth
def combat_items(session_id: str):
    """
    Get combat items bottom sheet (consumables only).

    Returns a bottom sheet UI with only consumable items that can be used in combat.
    """
    client = get_api_client()

    try:
        # Get session to find character
        session_response = client.get(f'/api/v1/sessions/{session_id}')
        session_data = session_response.get('result', {})
        character_id = session_data.get('character_id')

        # Get character inventory - filter to consumables only
        consumables = []
        if character_id:
            try:
                inv_response = client.get(f'/api/v1/characters/{character_id}/inventory')
                inv_data = inv_response.get('result', {})
                inventory = inv_data.get('inventory', [])

                # Filter to consumable items only
                for item in inventory:
                    item_type = item.get('item_type', item.get('type', ''))
                    if item_type == 'consumable' or item.get('usable_in_combat', False):
                        consumables.append({
                            'item_id': item.get('item_id'),
                            'name': item.get('name', 'Unknown Item'),
                            'description': item.get('description', ''),
                            'effects_on_use': item.get('effects_on_use', []),
                            'rarity': item.get('rarity', 'common')
                        })
            except (APINotFoundError, APIError) as e:
                logger.warning("failed_to_load_combat_inventory", character_id=character_id, error=str(e))

        return render_template(
            'game/partials/combat_items_sheet.html',
            session_id=session_id,
            consumables=consumables,
            has_consumables=len(consumables) > 0
        )

    except APIError as e:
        logger.error("failed_to_load_items", session_id=session_id, error=str(e))
        return f'''
        <div class="combat-items-sheet open">
            <div class="sheet-handle"></div>
            <div class="sheet-header">
                <h3>Use Item</h3>
                <button class="sheet-close" onclick="closeCombatSheet()">&times;</button>
            </div>
            <div class="sheet-body">
                <div class="no-consumables">Failed to load items: {e}</div>
            </div>
        </div>
        <div class="sheet-backdrop" onclick="closeCombatSheet()"></div>
        '''


@combat_bp.route('/<session_id>/items/<item_id>/detail')
@require_auth
def combat_item_detail(session_id: str, item_id: str):
    """Get item detail for combat bottom sheet."""
    client = get_api_client()

    try:
        # Get session to find character
        session_response = client.get(f'/api/v1/sessions/{session_id}')
        session_data = session_response.get('result', {})
        character_id = session_data.get('character_id')

        item = None
        if character_id:
            # Get inventory and find the item
            inv_response = client.get(f'/api/v1/characters/{character_id}/inventory')
            inv_data = inv_response.get('result', {})
            inventory = inv_data.get('inventory', [])

            for inv_item in inventory:
                if inv_item.get('item_id') == item_id:
                    item = inv_item
                    break

        if not item:
            return '<p>Item not found</p>', 404

        # Format effect description
        effect_desc = item.get('description', 'Use this item')
        effects = item.get('effects_on_use', [])
        if effects:
            effect_parts = []
            for effect in effects:
                if effect.get('stat') == 'hp':
                    effect_parts.append(f"Restores {effect.get('value', 0)} HP")
                elif effect.get('stat') == 'mp':
                    effect_parts.append(f"Restores {effect.get('value', 0)} MP")
                elif effect.get('name'):
                    effect_parts.append(effect.get('name'))
            if effect_parts:
                effect_desc = ', '.join(effect_parts)

        return f'''
        <div class="detail-info">
            <div class="detail-name">{item.get('name', 'Item')}</div>
            <div class="detail-effect">{effect_desc}</div>
        </div>
        <button class="use-btn"
                hx-post="{url_for('combat.combat_action', session_id=session_id)}"
                hx-vals='{{"action_type": "item", "item_id": "{item_id}"}}'
                hx-target="#combat-log"
                hx-swap="beforeend"
                onclick="closeCombatSheet()">
            Use
        </button>
        '''

    except APIError as e:
        logger.error("failed_to_load_combat_item_detail", session_id=session_id, item_id=item_id, error=str(e))
        return f'<p>Failed to load item: {e}</p>', 500


@combat_bp.route('/<session_id>/flee', methods=['POST'])
@require_auth
def combat_flee(session_id: str):
    """Attempt to flee from combat."""
    client = get_api_client()

    try:
        response = client.post(f'/api/v1/combat/{session_id}/flee', {})
        result = response.get('result', {})

        if result.get('success'):
            # Flee successful - use HX-Redirect for HTMX
            resp = make_response(f'''
            <div class="combat-log__entry combat-log__entry--system">
                <span class="log-message">{result.get('message', 'You fled from combat!')}</span>
            </div>
            ''')
            resp.headers['HX-Redirect'] = url_for('game.play_session', session_id=session_id)
            return resp
        else:
            # Flee failed - return log entry, trigger enemy turn
            resp = make_response(f'''
            <div class="combat-log__entry combat-log__entry--system">
                <span class="log-message">{result.get('message', 'Failed to flee!')}</span>
            </div>
            ''')
            # Failed flee consumes turn, so trigger enemy turn if needed
            if not result.get('next_is_player', True):
                resp.headers['HX-Trigger'] = 'enemyTurn'
            return resp

    except APIError as e:
        logger.error("flee_failed", session_id=session_id, error=str(e))
        return f'''
        <div class="combat-log__entry combat-log__entry--system">
            <span class="log-message">Flee failed: {e}</span>
        </div>
        ''', 500


@combat_bp.route('/<session_id>/enemy-turn', methods=['POST'])
@require_auth
def combat_enemy_turn(session_id: str):
    """Execute enemy turn and return result."""
    client = get_api_client()

    try:
        response = client.post(f'/api/v1/combat/{session_id}/enemy-turn', {})
        result = response.get('result', {})

        # Check if combat ended
        combat_ended = result.get('combat_ended', False)
        combat_status = result.get('combat_status')

        if combat_ended:
            # API returns lowercase status values: 'victory', 'defeat', 'fled'
            status_lower = (combat_status or '').lower()
            if status_lower == 'victory':
                return render_template(
                    'game/partials/combat_victory.html',
                    session_id=session_id,
                    rewards=result.get('rewards', {})
                )
            elif status_lower == 'defeat':
                return render_template(
                    'game/partials/combat_defeat.html',
                    session_id=session_id,
                    gold_lost=result.get('gold_lost', 0),
                    can_retry=result.get('can_retry', False)
                )

        # Format enemy action for log
        # API returns ActionResult directly in result, not nested under action_result
        log_entries = [{
            'actor': 'Enemy',
            'message': result.get('message', 'attacks'),
            'type': 'enemy',
            'is_crit': False
        }]

        # Add damage info - API returns total_damage, not damage
        damage_results = result.get('damage_results', [])
        if damage_results:
            log_entries[0]['damage'] = damage_results[0].get('total_damage')
            log_entries[0]['is_crit'] = damage_results[0].get('is_critical', False)

        # Check if it's still enemy turn (multiple enemies)
        resp = make_response(render_template(
            'game/partials/combat_log.html',
            combat_log=log_entries
        ))

        # If next combatant is also an enemy, trigger another enemy turn
        if result.get('next_combatant_id') and not result.get('next_is_player', True):
            resp.headers['HX-Trigger'] = 'enemyTurn'

        return resp

    except APIError as e:
        logger.error("enemy_turn_failed", session_id=session_id, error=str(e))
        return f'''
        <div class="combat-log__entry combat-log__entry--system">
            <span class="log-message">Enemy turn error: {e}</span>
        </div>
        ''', 500


@combat_bp.route('/<session_id>/log')
@require_auth
def combat_log(session_id: str):
    """Get current combat log."""
    client = get_api_client()

    try:
        response = client.get(f'/api/v1/combat/{session_id}/state')
        result = response.get('result', {})
        combat_log_data = result.get('combat_log', [])

        # Format log entries
        formatted_log = []
        for entry in combat_log_data:
            log_entry = {
                'actor': entry.get('combatant_name', entry.get('actor', '')),
                'message': entry.get('message', ''),
                'damage': entry.get('damage'),
                'heal': entry.get('healing'),
                'is_crit': entry.get('is_critical', False),
                'type': 'player' if entry.get('is_player', False) else 'enemy'
            }
            if entry.get('action_type') in ('round_start', 'combat_start', 'combat_end'):
                log_entry['type'] = 'system'
            formatted_log.append(log_entry)

        return render_template(
            'game/partials/combat_log.html',
            combat_log=formatted_log
        )

    except APIError as e:
        logger.error("failed_to_load_combat_log", session_id=session_id, error=str(e))
        return '<div class="combat-log__empty">Failed to load combat log</div>', 500


@combat_bp.route('/<session_id>/results')
@require_auth
def combat_results(session_id: str):
    """Display combat results (victory/defeat)."""
    client = get_api_client()

    try:
        response = client.get(f'/api/v1/combat/{session_id}/results')
        results = response.get('result', {})

        return render_template(
            'game/combat_results.html',
            victory=results['victory'],
            xp_gained=results['xp_gained'],
            gold_gained=results['gold_gained'],
            loot=results['loot']
        )

    except APIError as e:
        logger.error("failed_to_load_combat_results", session_id=session_id, error=str(e))
        return redirect(url_for('game.play_session', session_id=session_id))
