import 'dart:async'; // StreamController 사용을 위해 import
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; // For context.read in _prepareNextStage
import '../game/model/entity.dart';
import '../game/model/item.dart';
import '../game/model/status_effect.dart';
import '../game/model/stage.dart';
import '../game/data/item_table.dart';

import '../game/data/enemy_table.dart';
import '../game/data/player_table.dart';
import '../utils/game_math.dart';
import '../game/enums.dart';
import '../game/model/damage_event.dart'; // DamageEvent import
import '../game/model/effect_event.dart'; // EffectEvent import

import '../game/save_manager.dart';
import '../game/config/game_config.dart';
import '../game/config/battle_config.dart'; // Import BattleConfig
import 'shop_provider.dart'; // Import ShopProvider

import '../game/logic/battle_log_manager.dart';
import '../game/logic/combat_calculator.dart';

class EnemyIntent {
  final EnemyActionType type;
  final int value;
  final RiskLevel risk;
  final String description;
  final bool isSuccess;
  final int finalValue;

  EnemyIntent({
    required this.type,
    required this.value,
    required this.risk,
    required this.description,
    required this.isSuccess,
    required this.finalValue,
  });
}

class BattleProvider with ChangeNotifier {
  late Character player;
  late Character enemy; // Kept for compatibility, active during Battle/Elite

  late StageModel currentStage; // The current stage object
  EnemyIntent? currentEnemyIntent;

  final BattleLogManager _logManager = BattleLogManager();
  bool isPlayerTurn = true;

  int stage = 1;
  int turnCount = 1;
  List<Item> rewardOptions = [];
  bool showRewardPopup = false;
  int _lastGoldReward = 0; // New: Stores gold gained from last victory

  List<String> get logs => _logManager.logs;
  int get lastGoldReward => _lastGoldReward;

  void refreshUI() {
    notifyListeners();
  }

  // Damage Event Stream
  final _damageEventController = StreamController<DamageEvent>.broadcast();
  Stream<DamageEvent> get damageStream => _damageEventController.stream;

  // Effect Event Stream
  final _effectEventController = StreamController<EffectEvent>.broadcast();
  Stream<EffectEvent> get effectStream => _effectEventController.stream;

  // Dependency injection
  final ShopProvider shopProvider;

  BattleProvider({required this.shopProvider}) {
    // initializeBattle(); // Do not auto-start logic
  }

  @override
  void dispose() {
    _damageEventController.close(); // StreamController 닫기
    _effectEventController.close();
    super.dispose();
  }

  void loadFromSave(Map<String, dynamic> data) {
    stage = data['stage'];
    turnCount = data['turnCount'];
    player = Character.fromJson(data['player']);

    _logManager.clear();
    _addLog("Game Loaded! Resuming Stage $stage");

    _prepareNextStage();
    notifyListeners();
  }

  void initializeBattle() {
    stage = 1;
    turnCount = 1;
    // Load player from PlayerTable
    final playerTemplate = PlayerTable.get("warrior");
    if (playerTemplate != null) {
      player = playerTemplate.createCharacter();
    } else {
      // Fallback if data is missing
      player = Character(
        name: "Player",
        maxHp: 50,
        armor: 0,
        atk: 5,
        baseDefense: 5,
      );
    }

    // Give test gold
    player.gold = GameConfig.startingGold;

    // Provide starter equipment
    // final starterSword = Item(
    //   id: "starter_sword",
    //   name: "Wooden Sword",
    //   description: "A basic sword",
    //   atkBonus: 5,
    //   hpBonus: 0,
    //   slot: EquipmentSlot.weapon,
    // );
    // final starterArmor = Item(
    //   id: "starter_armor",
    //   name: "Leather Armor",
    //   description: "Basic protection",
    //   atkBonus: 0,
    //   hpBonus: 20,
    //   slot: EquipmentSlot.armor,
    // );
    // final starterShield = Item(
    //   id: "starter_shield",
    //   name: "Wooden Shield",
    //   description: "A small shield",
    //   atkBonus: 0,
    //   hpBonus: 0,
    //   armorBonus: 3,
    //   slot: EquipmentSlot.shield,
    // );
    // final starterRing = Item(
    //   id: "starter_ring",
    //   name: "Copper Ring",
    //   description: "A simple ring",
    //   atkBonus: 1,
    //   hpBonus: 5,
    //   slot: EquipmentSlot.accessory,
    // );

    // player.addToInventory(starterSword);
    // player.equip(starterSword);

    // player.addToInventory(starterArmor);
    // player.equip(starterArmor);

    // player.addToInventory(starterShield);
    // player.equip(starterShield);

    // player.addToInventory(starterRing);
    // player.equip(starterRing);

    // Add new status effect items for testing
    player.addToInventory(ItemTable.weapons[3].createItem()); // Stunning Hammer
    player.addToInventory(ItemTable.weapons[4].createItem()); // Jagged Dagger
    player.addToInventory(ItemTable.weapons[5].createItem()); // Sunderer Axe
    player.addToInventory(ItemTable.shields[3].createItem()); // Cursed Shield

    _prepareNextStage();
    _logManager.clear();
    _addLog("Game Started! Stage 1");
    notifyListeners();
  }

  void _prepareNextStage() {
    // Save Game at the start of each stage
    SaveManager.saveGame(this);

    StageType type;

    // Stage Type Logic
    if (stage % GameConfig.eliteStageInterval == 0) {
      type = StageType.elite; // Every 10th stage is a Boss/Elite
    } else if (stage % GameConfig.shopStageInterval == 0) {
      type = StageType.shop; // Every 5th stage is a Shop (except 10, 20...)
    } else if (stage % GameConfig.restStageInterval == 0) {
      type = StageType.rest; // Every 8th stage is a Rest
    } else {
      type = StageType.battle;
    }

    // Prepare Data based on Type
    Character? newEnemy;
    List<Item> shopItems = [];

    if (type == StageType.battle || type == StageType.elite) {
      bool isElite = type == StageType.elite;
      
      EnemyTemplate template = EnemyTable.getRandomEnemy(stage: stage, isElite: isElite);

      newEnemy = template.createCharacter(stage: stage);

      // Assign to the main 'enemy' field for UI compatibility
      enemy = newEnemy;
      isPlayerTurn = true;
      showRewardPopup = false;

      _generateEnemyIntent(); // Generate first intent

      _addLog("Stage $stage ($type) started! A wild ${enemy.name} appeared.");
    } else if (type == StageType.shop) {
      // Generate random items for shop using ShopProvider
      shopProvider.generateShopItems(stage);
      shopItems = shopProvider.availableItems;

      // Dummy enemy to prevent null errors in existing UI (until UI is fully updated)
      enemy = Character(name: "Merchant", maxHp: 9999, armor: 0, atk: 0);

      _addLog("Stage $stage: Entered a Shop.");
    } else if (type == StageType.rest) {
      // Dummy enemy
      enemy = Character(name: "Campfire", maxHp: 9999, armor: 0, atk: 0);
      _addLog("Stage $stage: Found a safe resting spot.");
    }

    currentStage = StageModel(
      type: type,
      enemy: newEnemy,
      shopItems: shopItems, // Pass items from ShopProvider
    );
    turnCount = 1;
    notifyListeners();
  }

  // Shop-related methods are now handled by ShopProvider

  // Replaces _spawnEnemy
  // void _spawnEnemy() { ... } - Removed

  Future<void> _onDefeat() async {
    _addLog("Player defeated! Enemy wins!");
    await SaveManager.clearSaveData();
    notifyListeners();
  }

  /// Handle player's action choice

  Future<void> playerAction(ActionType type, RiskLevel risk) async {
    if (!isPlayerTurn || player.isDead || enemy.isDead || showRewardPopup)
      return;

    // Update Enemy Status Effects at the start of Player's turn (user request)
    enemy.updateStatusEffects();

    // 1. Check for Defense Forbidden status
    if (type == ActionType.defend &&
        player.hasStatus(StatusEffectType.defenseForbidden)) {
      _addLog("Cannot defend! You are under Defense Forbidden status.");
      notifyListeners(); // 상태 변경을 알림
      _endPlayerTurn();
      return;
    }

    isPlayerTurn = false;
    notifyListeners();

    // 2. Process Start-of-Turn Effects (Stun, Bleed)
    bool canAct = _processStartTurnEffects(player);
    
    if (player.isDead) {
      await _onDefeat();
      return;
    }

    if (!canAct) {
      _endPlayerTurn(); // Skip turn if stunned
      return;
    }

    _addLog("Player chose to ${type.name} with ${risk.name} risk.");

    // Calculate Outcome using CombatCalculator
    int baseValue = (type == ActionType.attack) ? player.totalAtk : player.totalDefense;
    
    final result = CombatCalculator.calculateActionOutcome(
      risk: risk, 
      luck: player.totalLuck, 
      baseValue: baseValue
    );

    if (result.success) {
      if (type == ActionType.attack) {
        int damage = result.value;

        final eventId =
            DateTime.now().millisecondsSinceEpoch.toString() +
            Random().nextInt(1000).toString();
        _effectEventController.sink.add(
          EffectEvent(
            id: eventId,
            type: ActionType.attack,
            risk: risk,
            target: EffectTarget.enemy,
            feedbackType: null, 
          ),
        );

        // Animation Delays
        int delay = GameConfig.animDelayNormal;
        if (risk == RiskLevel.safe) delay = GameConfig.animDelaySafe;
        if (risk == RiskLevel.risky) delay = GameConfig.animDelayRisky;
        
        await Future.delayed(Duration(milliseconds: delay));

        // Calculate Damage to HP using CombatCalculator
        int damageToHp = CombatCalculator.calculateDamageToHp(
          incomingDamage: damage, 
          currentArmor: enemy.armor, 
          isVulnerable: enemy.hasStatus(StatusEffectType.vulnerable)
        );

        // Calculate Remaining Armor
        int remainingArmor = CombatCalculator.calculateRemainingArmor(
            incomingDamage: damage, 
            currentArmor: enemy.armor, 
            isVulnerable: enemy.hasStatus(StatusEffectType.vulnerable)
        );
        
        // Log details
        if (enemy.armor > 0) {
             int absorbed = enemy.armor - remainingArmor;
             if (damageToHp == 0) {
                 _addLog("Enemy's armor absorbed all damage.");
             } else {
                 _addLog("Enemy's armor absorbed $absorbed damage.");
             }
        }
        
        enemy.armor = remainingArmor;

        if (damageToHp > 0) {
          // Note: _applyDamage internally handles Vulnerable multiplier again for the DamageEvent and logs.
          // To avoid double application, we should just pass the raw damage to _applyDamage 
          // OR refactor _applyDamage.
          // Let's refactor _applyDamage to just apply the final value since we calculated it here.
          // actually _applyDamage handles the reduction of HP.
          // Let's call a simplified version or just do it here.
          
          enemy.hp -= damageToHp;
          if (enemy.hp < 0) enemy.hp = 0;
          
          _damageEventController.sink.add(
              DamageEvent(
                  damage: damageToHp, 
                  target: DamageTarget.enemy, 
                  type: enemy.hasStatus(StatusEffectType.vulnerable) ? DamageType.vulnerable : DamageType.normal
              ),
          );
          _addLog("Player dealt $damageToHp damage to Enemy.");
        } else {
          _addLog("Player's attack was fully blocked by armor.");
        }

        // Try applying status effects
        _tryApplyStatusEffects(player, enemy);
      } else {
        // Defense Success
        _effectEventController.sink.add(
          EffectEvent(
            id:
                DateTime.now().millisecondsSinceEpoch.toString() +
                Random().nextInt(1000).toString(),
            type: ActionType.defend,
            risk: risk,
            target: EffectTarget.player,
            feedbackType: null, 
          ),
        );

        int armorGained = result.value;
        player.armor += armorGained;
        _addLog("Player gained $armorGained armor.");
      }
    } else {
      // Failure
      if (type == ActionType.attack) {
        _addLog("Player's attack missed!");
        _effectEventController.sink.add(
          EffectEvent(
            id:
                DateTime.now().millisecondsSinceEpoch.toString() +
                Random().nextInt(1000).toString(),
            type: type,
            risk: risk,
            target: EffectTarget.enemy, 
            feedbackType: BattleFeedbackType.miss,
          ),
        );
      } else {
        _addLog("Player's defense failed!");
        _effectEventController.sink.add(
          EffectEvent(
            id:
                DateTime.now().millisecondsSinceEpoch.toString() +
                Random().nextInt(1000).toString(),
            type: type,
            risk: risk,
            target: EffectTarget.player, 
            feedbackType: BattleFeedbackType.failed,
          ),
        );
      }
    }

    if (enemy.isDead) {
      _onVictory();
      return;
    }

    _endPlayerTurn();
  }

  void _endPlayerTurn() {
    // Update durations at end of turn
    player.updateStatusEffects();

    // Check if enemy is dead from bleed
    if (enemy.isDead) {
      _onVictory();
      return;
    }

    Future.delayed(
      const Duration(milliseconds: GameConfig.animDelayEnemyTurn),
      () => _enemyTurn(),
    );
  }

  Future<void> _enemyTurn() async {
    if (!isPlayerTurn && (player.isDead || enemy.isDead)) return;

    _addLog("Enemy's turn...");
    await Future.delayed(
      const Duration(milliseconds: GameConfig.animDelayEnemyTurn),
    );

    // Enemy Turn Start Logic
    // Armor decay
    if (enemy.armor > 0) {
      enemy.armor = (enemy.armor * GameConfig.armorDecayRate).toInt();
      _addLog("Enemy's armor decayed to ${enemy.armor}.");
    }

    // 1. Process Start-of-Turn Effects for Enemy
    bool canAct = _processStartTurnEffects(enemy);

    // Check death from bleed before acting
    if (enemy.isDead) {
      _onVictory();
      return;
      // return; // Already handled by _processStartTurnEffects if damage applied
    }

    if (canAct && currentEnemyIntent != null) {
      final intent = currentEnemyIntent!;

      if (intent.type == EnemyActionType.defend) {
        // Already handled in _generateEnemyIntent
        _addLog("Enemy maintains defensive stance.");
      } else {
        // Attack Logic
        if (intent.isSuccess) {
          _effectEventController.sink.add(
            EffectEvent(
              id:
                  DateTime.now().millisecondsSinceEpoch.toString() +
                  Random().nextInt(1000).toString(),
              type: ActionType.attack,
              risk: intent.risk,
              target: EffectTarget.player,
              feedbackType: null, // 공격 성공이므로 feedbackType 없음
            ),
          );

          int incomingDamage = intent.finalValue;
          
          // Calculate Damage using Calculator
          int damageToHp = CombatCalculator.calculateDamageToHp(
              incomingDamage: incomingDamage, 
              currentArmor: player.armor, 
              isVulnerable: player.hasStatus(StatusEffectType.vulnerable)
          );
          
          int remainingArmor = CombatCalculator.calculateRemainingArmor(
              incomingDamage: incomingDamage, 
              currentArmor: player.armor, 
              isVulnerable: player.hasStatus(StatusEffectType.vulnerable)
          );

           if (player.armor > 0) {
             int absorbed = player.armor - remainingArmor;
             if (damageToHp == 0) {
                 _addLog("Armor absorbed all damage.");
             } else {
                 _addLog("Armor absorbed $absorbed damage.");
             }
           }
           player.armor = remainingArmor;

          if (damageToHp > 0) {
             player.hp -= damageToHp;
             if (player.hp < 0) player.hp = 0;

             _damageEventController.sink.add(
              DamageEvent(
                  damage: damageToHp, 
                  target: DamageTarget.player, 
                  type: player.hasStatus(StatusEffectType.vulnerable) ? DamageType.vulnerable : DamageType.normal
              ),
            );
            _addLog("Enemy dealt $damageToHp damage to Player HP.");
          }

          // Try applying status effects from enemy equipment
          _tryApplyStatusEffects(enemy, player);
        } else {
          _addLog("Enemy's ${intent.risk.name} attack missed!");
          _effectEventController.sink.add(
            EffectEvent(
              id:
                  DateTime.now().millisecondsSinceEpoch.toString() +
                  Random().nextInt(1000).toString(),
              type: ActionType.attack, // 적의 공격이므로 ActionType.attack
              risk: intent.risk,
              target: EffectTarget.player, // 플레이어가 회피했으므로 플레이어 위치에 이펙트
              feedbackType: BattleFeedbackType.miss, // 변경: MISS 피드백
            ),
          );
        }
      }
    } else if (!canAct) {
      _addLog("Enemy is stunned and cannot act!");
    } else {
      _addLog("Enemy did nothing.");
    }

    // Generate next intent
    if (!player.isDead) {
      _generateEnemyIntent();
    }

    // Player Turn Start Logic
    // Armor decay
    if (player.armor > 0) {
      player.armor = (player.armor * GameConfig.armorDecayRate).toInt();
      _addLog("Player's armor decayed to ${player.armor}.");
    }

    if (player.isDead) {
      await _onDefeat();
      return;
    }

    isPlayerTurn = true;
    turnCount++;
    notifyListeners();
  }

  /// Process effects that happen at the start of the turn (Bleed, Stun).
  /// Returns true if the character can act, false if stunned.
  bool _processStartTurnEffects(Character character) {
    final result = CombatCalculator.processStartTurnEffects(character);
    
    int totalBleed = result['bleedDamage'];
    bool isStunned = result['isStunned'];

    // 1. Bleed Damage
    if (totalBleed > 0) {
      character.hp -= totalBleed;
      if (character.hp < 0) character.hp = 0;
      _addLog("${character.name} takes $totalBleed bleed damage!");

      // Emit DamageEvent for bleed
      _damageEventController.sink.add(
        DamageEvent(
          damage: totalBleed,
          target: (character == player) ? DamageTarget.player : DamageTarget.enemy,
          type: DamageType.bleed,
        ),
      );
    }

    // 2. Stun Check
    if (isStunned) {
      _addLog("${character.name} is stunned!");
    }

    return !isStunned;
  }

  /// Tries to apply status effects from attacker's equipment to the target.
  void _tryApplyStatusEffects(Character attacker, Character target) {
    List<StatusEffect> effectsToApply = CombatCalculator.getAppliedEffects(attacker);
    
    for (var effect in effectsToApply) {
      target.addStatusEffect(effect);
      _addLog("Applied ${effect.type.name} to ${target.name}!");
    }
  }



  void _addLog(String message) {
    _logManager.addLog(message);
    notifyListeners();
  }

  void _onVictory() {
    // Calculate Gold Reward
    // Base 10 + (Stage * 5) + Random variance
    final random = Random();
    int goldReward = GameConfig.baseGoldReward + (stage * GameConfig.goldRewardPerStage) + random.nextInt(GameConfig.goldRewardVariance);

    player.gold += goldReward;
    _lastGoldReward = goldReward; // Store for UI display
    _addLog("Enemy defeated! Gained $goldReward Gold.");
    _addLog("Choose a reward.");

    ItemTier currentTier = ItemTier.tier1;
    if (stage > GameConfig.tier2StageMax)
      currentTier = ItemTier.tier3;
    else if (stage > GameConfig.tier1StageMax)
      currentTier = ItemTier.tier2;

    rewardOptions = [];
    
    bool isElite = currentStage.type == StageType.elite;
    bool isTier1 = currentTier == ItemTier.tier1;

    // Get 3 distinct items
    for (int i = 0; i < 3; i++) {
      ItemRarity? minRarity;
      ItemRarity? maxRarity;

      // 1. Elite Reward Logic (First Item only)
      if (isElite && i == 0) {
        if (isTier1) {
          // Tier 1 Elite: Guaranteed Rare
          minRarity = ItemRarity.rare;
          maxRarity = ItemRarity.rare; // Or allow higher? Request said "Guaranteed Rare 1 drop". Let's fix to Rare.
        } else {
          // Tier 2/3 Elite: Guaranteed Legendary
          minRarity = ItemRarity.legendary;
          // maxRarity = ItemRarity.legendary; // Optional, but let's allow Unique too if weights permit, or fix to Legendary. Request said "Guaranteed Legendary".
        }
      } 
      // 2. Standard Reward Logic (Others)
      else {
        if (isTier1) {
          // Tier 1 Normal/Other Rewards: Max Magic (No Rare+)
          maxRarity = ItemRarity.magic;
        }
        // Tier 2/3 Normal: No extra restrictions
      }

      ItemTemplate? item = ItemTable.getRandomItem(
        tier: currentTier, 
        minRarity: minRarity,
        maxRarity: maxRarity
      );
      
      if (item != null) {
        rewardOptions.add(item.createItem(stage: stage));
      }
    }

    // Add "None" (Skip) Option
    // We can represent "None" as a null or a special Item.
    // Using a special Item with ID "reward_skip" is safer for List<Item>.
    rewardOptions.add(
      Item(
        id: "reward_skip",
        name: "Skip Reward",
        description: "Take nothing and move on.",
        atkBonus: 0,
        hpBonus: 0,
        slot: EquipmentSlot.accessory,
      ),
    );

    showRewardPopup = true;
    notifyListeners();
  }

  bool selectReward(Item item) {
    if (item.id == "reward_skip") {
      _addLog("Skipped reward.");
      _completeStage();
      return true;
    } else {
      bool added = player.addToInventory(item);
      if (added) {
        _addLog("Added ${item.name} to inventory.");
        _completeStage();
        return true;
      } else {
        _addLog("Inventory is full! Could not take ${item.name}.");
        return false;
      }
    }
  }

  void _completeStage() {
    // Heal player after selecting reward
    int healAmount = GameMath.floor(
      player.totalMaxHp * GameConfig.stageHealRatio,
    );
    player.heal(healAmount);
    _addLog("Stage Cleared! Recovered $healAmount HP.");

    stage++;
    showRewardPopup = false;

    _prepareNextStage();

    // Log moved to _prepareNextStage

    // isPlayerTurn = true; // Handled in _prepareNextStage for battles
    notifyListeners();
  }

  void equipItem(Item item) {
    if (player.equip(item)) {
      _addLog("Equipped ${item.name}.");
    } else {
      _addLog(
        "Failed to equip ${item.name}.",
      ); // Should not happen if logic is correct
    }
    notifyListeners();
  }

  void unequipItem(Item item) {
    if (player.unequip(item)) {
      _addLog("Unequipped ${item.name}.");
    } else {
      _addLog("Failed to unequip ${item.name} (Inventory might be full).");
    }
    notifyListeners();
  }

  void discardItem(Item item) {
    if (player.inventory.remove(item)) {
      _addLog("Discarded ${item.name}.");
      notifyListeners();
    }
  }

  void sellItem(Item item) {
    if (player.inventory.remove(item)) {
      int sellPrice = GameMath.floor(
        item.price * GameConfig.sellPriceMultiplier,
      );
      player.gold += sellPrice;
      _addLog("Sold ${item.name} for $sellPrice G.");
      notifyListeners();
    }
  }

  /// Proceed to next stage from non-battle stages (Shop, Rest)
  void proceedToNextStage() {
    stage++;
    _prepareNextStage();
  }

  void _generateEnemyIntent() {
    if (enemy.isDead) {
      currentEnemyIntent = null;
      return;
    }

    final random = Random();

    // Decide Action Type
    // If baseDefense is 0, CANNOT defend.
    bool canDefend = enemy.baseDefense > 0;
    // Check for DefenseForbidden status
    if (enemy.hasStatus(StatusEffectType.defenseForbidden)) {
      canDefend = false;
    }
    bool isAttack = true;

    if (canDefend) {
      // 70% Attack, 30% Defend
      isAttack = random.nextDouble() < BattleConfig.enemyAttackChance;
    } else {
      isAttack = true;
    }

    // Decide Risk Level
    RiskLevel risk = RiskLevel.values[random.nextInt(RiskLevel.values.length)];
    double efficiency = 1.0;
    switch (risk) {
      case RiskLevel.safe:
        efficiency = BattleConfig.safeEfficiency;
        break;
      case RiskLevel.normal:
        efficiency = BattleConfig.normalEfficiency;
        break;
      case RiskLevel.risky:
        efficiency = BattleConfig.riskyEfficiency;
        break;
    }

    if (isAttack) {
      // Attack Intent
      // Variance removed as per request
      int damage = (enemy.totalAtk * efficiency).toInt();
      if (damage < 1) damage = 1;

      // Calculate success immediately
      bool success = false;
      switch (risk) {
        case RiskLevel.safe:
          success = random.nextDouble() < BattleConfig.safeBaseChance;
          break;
        case RiskLevel.normal:
          success = random.nextDouble() < BattleConfig.normalBaseChance;
          break;
        case RiskLevel.risky:
          success = random.nextDouble() < BattleConfig.riskyBaseChance;
          break;
      }

      currentEnemyIntent = EnemyIntent(
        type: EnemyActionType.attack,
        value: damage,
        risk: risk,
        description: "Attacks for $damage (${risk.name})",
        isSuccess: success,
        finalValue: damage,
      );
    } else {
      // Defend Intent
      int baseDef = enemy.totalDefense;
      // Variance removed
      int armor = (baseDef * 2 * efficiency).toInt();

      // Calculate success immediately
      bool success = false;
      switch (risk) {
        case RiskLevel.safe:
          success = random.nextDouble() < BattleConfig.safeBaseChance;
          break;
        case RiskLevel.normal:
          success = random.nextDouble() < BattleConfig.normalBaseChance;
          break;
        case RiskLevel.risky:
          success = random.nextDouble() < BattleConfig.riskyBaseChance;
          break;
      }

      currentEnemyIntent = EnemyIntent(
        type: EnemyActionType.defend,
        value: armor,
        risk: risk,
        description: "Defends for $armor (${risk.name})",
        isSuccess: success,
        finalValue: armor,
      );

      // Apply defense immediately if successful
      if (success) {
        enemy.armor += armor;
        _addLog("Enemy prepares defense! (+$armor Armor)");
        _effectEventController.sink.add(
          EffectEvent(
            id:
                DateTime.now().millisecondsSinceEpoch.toString() +
                Random().nextInt(1000).toString(),
            type: ActionType.defend,
            risk: risk,
            target: EffectTarget.enemy,
            feedbackType: null, // 방어 성공이므로 feedbackType 없음
          ),
        );
      } else {
        _addLog("Enemy tried to defend but fumbled!");
      }
    }
    notifyListeners();
  }
}
