import 'dart:math';

import 'package:asciineverdie/data/class_data.dart';
import 'package:asciineverdie/data/game_text_l10n.dart' as l10n;
import 'package:asciineverdie/data/race_data.dart';
import 'package:asciineverdie/src/core/engine/shop_service.dart';
import 'package:asciineverdie/src/core/model/class_traits.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/game_state.dart';
import 'package:asciineverdie/src/core/model/race_traits.dart';

/// 부활 시스템 서비스 (Phase 4)
///
/// 사망 처리, 부활 처리, 장비 상실 등을 담당
class ResurrectionService {
  const ResurrectionService({required this.shopService});

  final ShopService shopService;

  // ============================================================================
  // 사망 처리
  // ============================================================================

  /// 플레이어 사망 처리
  ///
  /// 1. 1개의 랜덤 장비 제거 (제물로 바침)
  /// 2. 전투 상태 초기화
  /// 3. 사망 정보 기록
  GameState processDeath({
    required GameState state,
    required String killerName,
    required DeathCause cause,
  }) {
    // 제물로 바칠 아이템 선택 (무기 제외, 장착된 아이템 중 랜덤 1개)
    final equippedItems = <int>[]; // 장착된 아이템의 슬롯 인덱스
    for (var i = 0; i < Equipment.slotCount; i++) {
      final slot = EquipmentSlot.values[i];
      // 무기 슬롯은 제외
      if (slot == EquipmentSlot.weapon) continue;

      final item = state.equipment.getItemByIndex(i);
      // 빈 슬롯 제외
      if (item.isNotEmpty) {
        equippedItems.add(i);
      }
    }

    String? lostItemName;
    EquipmentSlot? lostItemSlot;
    var newEquipment = state.equipment;

    if (equippedItems.isNotEmpty) {
      // 랜덤하게 1개 슬롯 선택
      final random = Random();
      final slotIndex = equippedItems[random.nextInt(equippedItems.length)];
      final lostItem = state.equipment.getItemByIndex(slotIndex);
      lostItemName = lostItem.name;
      lostItemSlot = EquipmentSlot.values[slotIndex];

      // 해당 슬롯만 빈 아이템으로 교체
      newEquipment = state.equipment.setItemByIndex(
        slotIndex,
        EquipmentItem.empty(lostItemSlot),
      );
    }

    // 사망 정보 생성
    final deathInfo = DeathInfo(
      cause: cause,
      killerName: killerName,
      lostEquipmentCount: lostItemName != null ? 1 : 0,
      lostItemName: lostItemName,
      lostItemSlot: lostItemSlot,
      goldAtDeath: state.inventory.gold,
      levelAtDeath: state.traits.level,
      timestamp: state.skillSystem.elapsedMs,
    );

    // 전투 상태 초기화
    final progress = state.progress.copyWith(clearCurrentCombat: true);

    return state.copyWith(
      equipment: newEquipment,
      progress: progress,
      deathInfo: deathInfo,
    );
  }

  // ============================================================================
  // 부활 처리
  // ============================================================================

  /// 플레이어 부활 처리
  ///
  /// 1. 골드로 구매 가능한 장비 자동 구매
  /// 2. HP/MP 전체 회복 (장비/종족/클래스 보너스 포함)
  /// 3. 사망 상태 해제
  /// 4. 안전 지역으로 이동 태스크 설정
  GameState processResurrection(GameState state) {
    if (!state.isDead) return state;

    // 1. 먼저 장비 구매 (HP 계산에 필요)
    final autoBuyResult = shopService.autoBuyForEmptySlots(
      playerLevel: state.traits.level,
      currentGold: state.inventory.gold,
      currentEquipment: state.equipment,
    );

    // 장비 적용
    var nextState = state.copyWith(
      equipment: autoBuyResult.updatedEquipment,
      inventory: state.inventory.copyWith(gold: autoBuyResult.remainingGold),
    );

    // 2. 전체 HP/MP 계산 (장비 + 종족 + 클래스 보너스 포함)
    final totalHpMax = _calculateTotalHpMax(nextState);
    final totalMpMax = _calculateTotalMpMax(nextState);

    // HP/MP 전체 회복
    nextState = nextState.copyWith(
      stats: nextState.stats.copyWith(
        hpCurrent: totalHpMax,
        mpCurrent: totalMpMax,
      ),
      clearDeathInfo: true, // 사망 상태 해제
    );

    // 스킬 쿨타임 초기화
    nextState = nextState.copyWith(
      skillSystem: SkillSystemState.empty().copyWith(
        elapsedMs: nextState.skillSystem.elapsedMs,
      ),
    );

    // 4. 부활 후 태스크 시퀀스 설정 (큐에 추가)
    // 순서: 마을 귀환 → 샵 정비 → 사냥터 이동 → 전투
    final resurrectionQueue = <QueueEntry>[
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 3000, // 3초
        caption: l10n.taskReturningToTown,
        taskType: TaskType.neutral, // 걷기 애니메이션
      ),
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 3000, // 3초
        caption: l10n.taskRestockingAtShop,
        taskType: TaskType.market, // town 애니메이션
      ),
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 2000, // 2초
        caption: l10n.taskHeadingToHuntingGrounds,
        taskType: TaskType.neutral, // 걷기 애니메이션
      ),
    ];

    // 기존 큐 초기화 후 부활 시퀀스만 설정
    // 첫 번째 태스크를 현재 태스크로 설정하여 즉시 표시
    final firstTask = resurrectionQueue.removeAt(0);
    nextState = nextState.copyWith(
      queue: QueueState(
        entries: resurrectionQueue, // 나머지 큐
      ),
      // 첫 번째 태스크를 현재 태스크로 직접 설정
      progress: nextState.progress.copyWith(
        currentTask: TaskInfo(
          caption: firstTask.caption,
          type: firstTask.taskType,
        ),
        task: ProgressBarState(position: 0, max: firstTask.durationMillis),
        currentCombat: null, // 전투 상태 명시적 초기화
      ),
    );

    return nextState;
  }

  /// 장비/종족/클래스 보너스를 포함한 전체 HP 계산
  int _calculateTotalHpMax(GameState state) {
    // 기본 HP + 장비 보너스
    var totalHp = state.stats.hpMax + state.equipment.totalStats.hpBonus;

    // 종족 HP 보너스 (예: Heap Troll +20%)
    final race = RaceData.findById(state.traits.raceId);
    if (race != null) {
      final raceHpBonus = race.getPassiveValue(PassiveType.hpBonus);
      if (raceHpBonus > 0) {
        totalHp = (totalHp * (1 + raceHpBonus)).round();
      }
    }

    // 클래스 HP 보너스 (예: Garbage Collector +30%)
    final klass = ClassData.findById(state.traits.classId);
    if (klass != null) {
      final classHpBonus = klass.getPassiveValue(ClassPassiveType.hpBonus);
      if (classHpBonus > 0) {
        totalHp = (totalHp * (1 + classHpBonus)).round();
      }
    }

    return totalHp;
  }

  /// 장비/종족/클래스 보너스를 포함한 전체 MP 계산
  int _calculateTotalMpMax(GameState state) {
    // 기본 MP + 장비 보너스
    var totalMp = state.stats.mpMax + state.equipment.totalStats.mpBonus;

    // 종족 MP 보너스 (예: Pointer Fairy +20%)
    final race = RaceData.findById(state.traits.raceId);
    if (race != null) {
      final raceMpBonus = race.getPassiveValue(PassiveType.mpBonus);
      if (raceMpBonus > 0) {
        totalMp = (totalMp * (1 + raceMpBonus)).round();
      }
    }

    return totalMp;
  }

  // ============================================================================
  // 유틸리티
  // ============================================================================

  /// 부활 비용 계산 (향후 확장용)
  ///
  /// 현재는 무료 부활, 향후 비용 도입 가능
  int calculateResurrectionCost(int playerLevel) {
    // 기본: 무료
    return 0;
  }

  /// 부활 가능 여부 확인
  bool canResurrect(GameState state) {
    if (!state.isDead) return false;

    final cost = calculateResurrectionCost(state.traits.level);
    return state.inventory.gold >= cost;
  }

  // ============================================================================
  // 광고 부활 (HP 100% + 아이템 복구)
  // ============================================================================

  /// 광고 부활 처리
  ///
  /// 1. 상실한 아이템 복구 (있는 경우)
  /// 2. HP/MP 100% 회복
  /// 3. 사망 상태 해제
  /// 4. 안전 지역으로 이동 태스크 설정
  ///
  /// Note: 10분 자동부활 버프는 GameSessionController에서 처리
  GameState processAdRevive(GameState state) {
    if (!state.isDead) return state;

    var nextState = state;

    // 1. 상실한 아이템 복구 (있는 경우)
    if (canRecoverLostItem(state)) {
      nextState = processItemRecovery(nextState);
    }

    // 2. 전체 HP/MP 계산 (장비 + 종족 + 클래스 보너스 포함)
    final totalHpMax = _calculateTotalHpMax(nextState);
    final totalMpMax = _calculateTotalMpMax(nextState);

    // HP/MP 100% 회복 (장비 구매 없이)
    nextState = nextState.copyWith(
      stats: nextState.stats.copyWith(
        hpCurrent: totalHpMax,
        mpCurrent: totalMpMax,
      ),
      clearDeathInfo: true, // 사망 상태 해제
    );

    // 스킬 쿨타임 초기화
    nextState = nextState.copyWith(
      skillSystem: SkillSystemState.empty().copyWith(
        elapsedMs: nextState.skillSystem.elapsedMs,
      ),
    );

    // 4. 부활 후 태스크 시퀀스 설정
    final resurrectionQueue = <QueueEntry>[
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 3000,
        caption: l10n.taskReturningToTown,
        taskType: TaskType.neutral,
      ),
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 3000,
        caption: l10n.taskRestockingAtShop,
        taskType: TaskType.market,
      ),
      QueueEntry(
        kind: QueueKind.task,
        durationMillis: 2000,
        caption: l10n.taskHeadingToHuntingGrounds,
        taskType: TaskType.neutral,
      ),
    ];

    final firstTask = resurrectionQueue.removeAt(0);
    nextState = nextState.copyWith(
      queue: QueueState(entries: resurrectionQueue),
      progress: nextState.progress.copyWith(
        currentTask: TaskInfo(
          caption: firstTask.caption,
          type: firstTask.taskType,
        ),
        task: ProgressBarState(position: 0, max: firstTask.durationMillis),
        currentCombat: null,
      ),
    );

    return nextState;
  }

  // ============================================================================
  // 아이템 복구 (Phase 5)
  // ============================================================================

  /// 상실한 아이템 복구 가능 여부 확인
  ///
  /// 사망 상태이고 상실한 아이템이 있을 때만 true
  bool canRecoverLostItem(GameState state) {
    if (!state.isDead) return false;
    if (state.deathInfo == null) return false;
    return state.deathInfo!.lostItem != null;
  }

  /// 상실한 아이템 복구 처리
  ///
  /// 광고 시청 후 호출되며 상실한 아이템을 장비에 복원합니다.
  /// Returns: 복구된 상태 (복구 불가 시 원본 상태 반환)
  GameState processItemRecovery(GameState state) {
    if (!canRecoverLostItem(state)) return state;

    final deathInfo = state.deathInfo!;
    final lostItem = deathInfo.lostItem!;
    final lostSlot = deathInfo.lostItemSlot!;

    // 해당 슬롯에 아이템 복원
    final slotIndex = lostSlot.index;
    final updatedEquipment = state.equipment.setItemByIndex(
      slotIndex,
      lostItem,
    );

    // DeathInfo에서 상실 아이템 정보 제거 (복구 완료)
    final updatedDeathInfo = deathInfo.copyWith(
      lostEquipmentCount: 0,
      lostItemName: null,
      lostItemSlot: null,
      lostItemRarity: null,
      lostItem: null,
    );

    return state.copyWith(
      equipment: updatedEquipment,
      deathInfo: updatedDeathInfo,
    );
  }

  /// 장비 보존 아이템 적용 (향후 확장용)
  ///
  /// [protectedSlots] 보존할 슬롯 인덱스 목록
  GameState processDeathWithProtection({
    required GameState state,
    required String killerName,
    required DeathCause cause,
    required List<int> protectedSlots,
  }) {
    // 보존할 아이템 추출
    final protectedItems = <int, EquipmentItem>{};
    for (final slotIndex in protectedSlots) {
      if (slotIndex >= 0 && slotIndex < Equipment.slotCount) {
        final item = state.equipment.getItemByIndex(slotIndex);
        if (item.isNotEmpty) {
          protectedItems[slotIndex] = item;
        }
      }
    }

    // 기본 사망 처리
    var nextState = processDeath(
      state: state,
      killerName: killerName,
      cause: cause,
    );

    // 보존된 아이템 복원
    var equipment = nextState.equipment;
    for (final entry in protectedItems.entries) {
      equipment = equipment.setItemByIndex(entry.key, entry.value);
    }

    // 상실 개수 재계산
    final actualLostCount =
        state.equipment.equippedItems.length - protectedItems.length;

    return nextState.copyWith(
      equipment: equipment,
      deathInfo: nextState.deathInfo?.copyWith(
        lostEquipmentCount: actualLostCount,
      ),
    );
  }
}
