import 'package:asciineverdie/src/core/engine/arena_combat_simulator.dart';
import 'package:asciineverdie/src/core/engine/combat_calculator.dart';
import 'package:asciineverdie/src/core/engine/item_service.dart';
import 'package:asciineverdie/src/core/model/arena_match.dart';
import 'package:asciineverdie/src/core/model/equipment_item.dart';
import 'package:asciineverdie/src/core/model/equipment_slot.dart';
import 'package:asciineverdie/src/core/model/hall_of_fame.dart';
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
import 'package:asciineverdie/src/core/util/deterministic_random.dart';

/// 아레나 서비스
///
/// 로컬 아레나 대전 시스템의 핵심 로직 담당:
/// - 순위 계산 및 상대 결정
/// - 전투 실행
/// - 장비 교환
class ArenaService {
  ArenaService({DeterministicRandom? rng})
    : _rng = rng ?? DeterministicRandom(DateTime.now().millisecondsSinceEpoch);

  final DeterministicRandom _rng;

  // ============================================================================
  // 상대 결정
  // ============================================================================

  /// 상대 결정 (바로 위 순위, 1위면 2위와 대결)
  ///
  /// [hallOfFame] 명예의 전당
  /// [challengerId] 도전자 캐릭터 ID
  /// Returns: 상대 캐릭터 (없으면 null)
  HallOfFameEntry? findOpponent(HallOfFame hallOfFame, String challengerId) {
    final ranked = hallOfFame.rankedEntries;
    if (ranked.length < 2) return null;

    final currentRank = hallOfFame.getRank(challengerId);
    if (currentRank <= 0) return null;

    // 1위면 2위와 대결
    if (currentRank == 1) {
      return ranked[1];
    }

    // 그 외는 바로 위 순위와 대결
    return ranked[currentRank - 2];
  }

  // ============================================================================
  // 전투 실행
  // ============================================================================

  /// 아레나 전투 실행
  ///
  /// [match] 대전 정보
  /// Returns: 대전 결과 (승패, 장비 교환 후 캐릭터)
  ArenaMatchResult executeCombat(ArenaMatch match) {
    final calculator = CombatCalculator(rng: _rng);

    // 도전자 스탯 (풀 HP로 시작)
    final challengerStats = match.challenger.finalStats;
    final opponentStats = match.opponent.finalStats;

    if (challengerStats == null || opponentStats == null) {
      // 스탯이 없으면 도전자 패배 처리
      return ArenaMatchResult(
        match: match,
        isVictory: false,
        turns: 0,
        updatedChallenger: match.challenger,
        updatedOpponent: match.opponent,
      );
    }

    // 플레이어 스탯 (풀 HP로 초기화)
    var playerCombatStats = challengerStats.copyWith(
      hpCurrent: challengerStats.hpMax,
      mpCurrent: challengerStats.mpMax,
    );

    // 상대를 몬스터 형태로 변환
    var opponentMonsterStats = MonsterCombatStats.fromCombatStats(
      opponentStats,
      match.opponent.characterName,
    );

    // 전투 시뮬레이션
    int turns = 0;
    int playerAccum = 0;
    int opponentAccum = 0;
    const tickMs = 200;

    while (playerCombatStats.isAlive && opponentMonsterStats.isAlive) {
      playerAccum += tickMs;
      opponentAccum += tickMs;

      // 플레이어 공격
      if (playerAccum >= playerCombatStats.attackDelayMs) {
        final result = calculator.playerAttackMonster(
          attacker: playerCombatStats,
          defender: opponentMonsterStats,
        );
        opponentMonsterStats = result.updatedDefender;
        playerAccum = 0;
        turns++;
      }

      // 상대 공격 (살아있을 때만)
      if (opponentMonsterStats.isAlive &&
          opponentAccum >= opponentMonsterStats.attackDelayMs) {
        final result = calculator.monsterAttackPlayer(
          attacker: opponentMonsterStats,
          defender: playerCombatStats,
        );
        playerCombatStats = result.updatedDefender;
        opponentAccum = 0;
      }

      // 무한 루프 방지
      if (turns > 1000) break;
    }

    final isVictory = playerCombatStats.isAlive;

    // 장비 교환
    final (updatedChallenger, updatedOpponent) = _exchangeEquipment(
      match: match,
      isVictory: isVictory,
    );

    return ArenaMatchResult(
      match: match,
      isVictory: isVictory,
      turns: turns,
      updatedChallenger: updatedChallenger,
      updatedOpponent: updatedOpponent,
    );
  }

  /// 시뮬레이션 결과를 기반으로 전투 결과 생성
  ///
  /// [match] 대전 정보
  /// [challengerHp] 도전자 최종 HP
  /// [opponentHp] 상대 최종 HP
  /// [turns] 총 턴 수
  /// Returns: 대전 결과 (승패, 장비 교환 후 캐릭터)
  ArenaMatchResult createResultFromSimulation({
    required ArenaMatch match,
    required int challengerHp,
    required int opponentHp,
    required int turns,
  }) {
    // 도전자 HP가 0보다 크면 승리
    final isVictory = challengerHp > 0 && opponentHp <= 0;

    // 장비 교환
    final (updatedChallenger, updatedOpponent) = _exchangeEquipment(
      match: match,
      isVictory: isVictory,
    );

    return ArenaMatchResult(
      match: match,
      isVictory: isVictory,
      turns: turns,
      updatedChallenger: updatedChallenger,
      updatedOpponent: updatedOpponent,
    );
  }

  /// 전투 시뮬레이션 (애니메이션용 스트림)
  ///
  /// ArenaCombatSimulator에 위임하여 턴별 전투 상황을 스트림으로 반환.
  Stream<ArenaCombatTurn> simulateCombat(ArenaMatch match) {
    final simulator = ArenaCombatSimulator(rng: _rng);
    return simulator.simulateCombat(match);
  }
  // ============================================================================
  // AI 베팅 슬롯 선택
  // ============================================================================

  /// AI가 도전자에게서 약탈할 슬롯 자동 선택
  ///
  /// 도전자의 가장 좋은 장비 슬롯 선택 (무기 제외)
  EquipmentSlot selectOpponentBettingSlot(HallOfFameEntry challenger) {
    final equipment = challenger.finalEquipment ?? [];
    if (equipment.isEmpty) {
      // 장비가 없으면 기본 슬롯 (투구)
      return EquipmentSlot.helm;
    }

    // 무기를 제외한 장비 중 가장 높은 점수의 슬롯 선택
    EquipmentSlot? bestSlot;
    int bestScore = -1;

    for (final item in equipment) {
      // 무기는 약탈 불가
      if (item.slot == EquipmentSlot.weapon) continue;
      if (item.isEmpty) continue;

      final score = ItemService.calculateEquipmentScore(item);
      if (score > bestScore) {
        bestScore = score;
        bestSlot = item.slot;
      }
    }

    // 유효한 슬롯이 없으면 투구 선택
    return bestSlot ?? EquipmentSlot.helm;
  }

  /// 베팅 가능한 슬롯 목록 반환 (무기 제외)
  List<EquipmentSlot> getBettableSlots() {
    return EquipmentSlot.values
        .where((slot) => slot != EquipmentSlot.weapon)
        .toList();
  }

  // ============================================================================
  // 장비 약탈
  // ============================================================================

  /// 장비 약탈 (승자가 패자의 베팅 슬롯 장비 획득)
  ///
  /// - 승자: 자신이 선택한 슬롯의 패자 장비 획득
  /// - 패자: 해당 슬롯 장비 손실 → 기본 장비로 대체
  (HallOfFameEntry, HallOfFameEntry) _exchangeEquipment({
    required ArenaMatch match,
    required bool isVictory,
  }) {
    // 도전자 장비 목록 복사
    final challengerEquipment = List<EquipmentItem>.from(
      match.challenger.finalEquipment ?? [],
    );

    // 상대 장비 목록 복사
    final opponentEquipment = List<EquipmentItem>.from(
      match.opponent.finalEquipment ?? [],
    );

    if (isVictory) {
      // 도전자 승리: 도전자가 선택한 슬롯의 상대 장비 획득
      final winnerSlot = match.challengerBettingSlot;
      final lootedItem = _findItemBySlot(opponentEquipment, winnerSlot);

      // 도전자: 약탈한 장비로 교체
      _replaceItemInList(challengerEquipment, winnerSlot, lootedItem);

      // 상대: 해당 슬롯 기본 장비로 대체
      final defaultItem = _createDefaultEquipment(winnerSlot);
      _replaceItemInList(opponentEquipment, winnerSlot, defaultItem);
    } else {
      // 상대 승리: 상대가 선택한 슬롯의 도전자 장비 획득
      final winnerSlot = match.opponentBettingSlot;
      final lootedItem = _findItemBySlot(challengerEquipment, winnerSlot);

      // 상대: 약탈한 장비로 교체
      _replaceItemInList(opponentEquipment, winnerSlot, lootedItem);

      // 도전자: 해당 슬롯 기본 장비로 대체
      final defaultItem = _createDefaultEquipment(winnerSlot);
      _replaceItemInList(challengerEquipment, winnerSlot, defaultItem);
    }

    // 업데이트된 엔트리 생성
    final updatedChallenger = match.challenger.copyWith(
      finalEquipment: challengerEquipment,
    );
    final updatedOpponent = match.opponent.copyWith(
      finalEquipment: opponentEquipment,
    );

    return (updatedChallenger, updatedOpponent);
  }

  /// 슬롯으로 장비 찾기
  EquipmentItem _findItemBySlot(
    List<EquipmentItem> equipment,
    EquipmentSlot slot,
  ) {
    for (final item in equipment) {
      if (item.slot == slot) return item;
    }
    return EquipmentItem.empty(slot);
  }

  /// 장비 목록에서 특정 슬롯의 아이템 교체
  void _replaceItemInList(
    List<EquipmentItem> equipment,
    EquipmentSlot slot,
    EquipmentItem newItem,
  ) {
    for (var i = 0; i < equipment.length; i++) {
      if (equipment[i].slot == slot) {
        equipment[i] = newItem;
        return;
      }
    }
    // 슬롯이 없으면 추가
    equipment.add(newItem);
  }

  /// 기본 장비 생성 (Common 등급)
  ///
  /// 패자가 장비를 잃었을 때 빈 슬롯 방지용
  EquipmentItem _createDefaultEquipment(EquipmentSlot slot) {
    return ItemService.createDefaultEquipmentForSlot(slot);
  }
}
