import 'package:asciineverdie/data/skill_data.dart';
import 'package:asciineverdie/src/core/model/combat_stats.dart';
import 'package:asciineverdie/src/core/model/game_state.dart';
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
import 'package:asciineverdie/src/core/model/skill.dart';
import 'package:asciineverdie/src/core/util/deterministic_random.dart';

/// 스킬 자동 선택 AI
///
/// SkillService에서 분리된 전투 중 스킬 자동 선택 로직.
/// 상황별 우선순위에 따라 최적의 스킬을 선택한다.
class SkillAutoSelector {
  const SkillAutoSelector({required this.rng});

  final DeterministicRandom rng;

  /// 전투 중 자동 스킬 선택
  ///
  /// 우선순위:
  /// 1. HP < 30% -> 회복 스킬 (최우선)
  /// 2. 70% 확률로 일반 공격 (MP 절약, 기본 전투)
  /// 3. 30% 확률로 스킬 사용:
  ///    - 버프: HP > 80% & MP > 60% & 활성 버프 없음
  ///    - 디버프: 몬스터 HP > 80% & 활성 디버프 없음
  ///    - DOT: 몬스터 HP > 60% & 활성 DOT 없음
  ///    - 공격: 보스전이면 강력한 스킬, 일반전이면 효율적 스킬
  /// 4. MP < 20% -> 일반 공격
  Skill? selectAutoSkill({
    required CombatStats player,
    required MonsterCombatStats monster,
    required SkillSystemState skillSystem,
    required List<String> availableSkillIds,
    required bool Function(Skill) canUse,
    List<DotEffect> activeDoTs = const [],
    List<ActiveBuff> activeDebuffs = const [],
  }) {
    final mpRatio = player.mpRatio;
    final hpRatio = player.hpRatio;

    // MP 20% 미만이면 일반 공격
    if (mpRatio < 0.2) return null;

    // 사용 가능한 스킬 필터링
    final availableSkills = availableSkillIds
        .map((id) => SkillData.getSkillById(id))
        .whereType<Skill>()
        .where(canUse)
        .toList();

    if (availableSkills.isEmpty) return null;

    // HP < 30% -> 회복 스킬 최우선 (생존)
    if (hpRatio < 0.3) {
      final healSkill = _findBestHealSkill(availableSkills, player.mpCurrent);
      if (healSkill != null) return healSkill;
    }

    // 70% 확률로 일반 공격 (스킬은 특별한 상황에서만)
    final useNormalAttack = rng.nextInt(100) < 70;
    if (useNormalAttack) return null;

    // === 아래부터 30% 확률로 스킬 사용 ===

    // 버프: HP > 80% & MP > 60% (매우 안전할 때만)
    if (hpRatio > 0.8 && mpRatio > 0.6) {
      final hasActiveBuff = skillSystem.activeBuffs.isNotEmpty;
      if (!hasActiveBuff) {
        final buffSkill = _findBestBuffSkill(availableSkills, player.mpCurrent);
        if (buffSkill != null) return buffSkill;
      }
    }

    // 디버프: 몬스터 HP > 80% & 활성 디버프 없음 (전투 초반)
    if (monster.hpRatio > 0.8 && activeDebuffs.isEmpty) {
      final debuffSkill = _findBestDebuffSkill(
        availableSkills,
        player.mpCurrent,
      );
      if (debuffSkill != null) return debuffSkill;
    }

    // DOT: 몬스터 HP > 60% & 활성 DOT 없음 (장기전 유리)
    if (monster.hpRatio > 0.6 && activeDoTs.isEmpty) {
      final dotSkill = _findBestDotSkill(availableSkills, player.mpCurrent);
      if (dotSkill != null) return dotSkill;
    }

    // 보스전 판단 (몬스터 레벨 20 이상 & HP 50% 이상)
    final isBossFight = monster.level >= 20 && monster.hpRatio > 0.5;

    if (isBossFight) {
      return _findStrongestAttackSkill(availableSkills);
    }

    // 일반 전투 -> MP 효율 좋은 공격 스킬
    return _findEfficientAttackSkill(availableSkills);
  }

  /// 가장 좋은 DOT 스킬 찾기
  Skill? _findBestDotSkill(List<Skill> skills, int currentMp) {
    final dotSkills = skills
        .where((s) => s.isDot && s.mpCost <= currentMp)
        .toList();

    if (dotSkills.isEmpty) return null;

    dotSkills.sort((a, b) {
      final aTotal =
          (a.baseDotDamage ?? 0) *
          ((a.baseDotDurationMs ?? 0) ~/ (a.baseDotTickMs ?? 1000));
      final bTotal =
          (b.baseDotDamage ?? 0) *
          ((b.baseDotDurationMs ?? 0) ~/ (b.baseDotTickMs ?? 1000));
      return bTotal.compareTo(aTotal);
    });

    return dotSkills.first;
  }

  /// 가장 좋은 회복 스킬 찾기
  Skill? _findBestHealSkill(List<Skill> skills, int currentMp) {
    final healSkills = skills
        .where((s) => s.isHeal && s.mpCost <= currentMp)
        .toList();

    if (healSkills.isEmpty) return null;

    healSkills.sort((a, b) {
      final aValue = a.healPercent * 100 + a.healAmount;
      final bValue = b.healPercent * 100 + b.healAmount;
      return bValue.compareTo(aValue);
    });

    return healSkills.first;
  }

  /// 가장 강력한 공격 스킬 찾기
  Skill? _findStrongestAttackSkill(List<Skill> skills) {
    final attackSkills = skills.where((s) => s.isAttack).toList();
    if (attackSkills.isEmpty) return null;

    attackSkills.sort(
      (a, b) => b.damageMultiplier.compareTo(a.damageMultiplier),
    );
    return attackSkills.first;
  }

  /// MP 효율 좋은 공격 스킬 찾기
  Skill? _findEfficientAttackSkill(List<Skill> skills) {
    final attackSkills = skills.where((s) => s.isAttack).toList();
    if (attackSkills.isEmpty) return null;

    attackSkills.sort((a, b) => b.mpEfficiency.compareTo(a.mpEfficiency));
    return attackSkills.first;
  }

  /// 가장 좋은 버프 스킬 찾기
  Skill? _findBestBuffSkill(List<Skill> skills, int currentMp) {
    final buffSkills = skills
        .where((s) => s.isBuff && s.mpCost <= currentMp && s.buff != null)
        .toList();

    if (buffSkills.isEmpty) return null;

    buffSkills.sort((a, b) {
      final aValue =
          (a.buff?.atkModifier ?? 0) +
          (a.buff?.defModifier ?? 0) * 0.5 +
          (a.buff?.criRateModifier ?? 0) * 0.3;
      final bValue =
          (b.buff?.atkModifier ?? 0) +
          (b.buff?.defModifier ?? 0) * 0.5 +
          (b.buff?.criRateModifier ?? 0) * 0.3;
      return bValue.compareTo(aValue);
    });

    return buffSkills.first;
  }

  /// 가장 좋은 디버프 스킬 찾기
  Skill? _findBestDebuffSkill(List<Skill> skills, int currentMp) {
    final debuffSkills = skills
        .where((s) => s.isDebuff && s.mpCost <= currentMp && s.buff != null)
        .toList();

    if (debuffSkills.isEmpty) return null;

    debuffSkills.sort((a, b) {
      final aValue =
          (a.buff?.atkModifier ?? 0).abs() +
          (a.buff?.defModifier ?? 0).abs() * 0.5;
      final bValue =
          (b.buff?.atkModifier ?? 0).abs() +
          (b.buff?.defModifier ?? 0).abs() * 0.5;
      return bValue.compareTo(aValue);
    });

    return debuffSkills.first;
  }
}
