// ignore_for_file: avoid_print
import 'package:asciineverdie/src/core/model/item_stats.dart';
import 'package:asciineverdie/src/core/util/balance_constants.dart';
import 'package:flutter_test/flutter_test.dart';

/// 전체 레벨 밸런스 분석 테스트
///
/// 이 테스트는 플레이어와 몬스터의 스탯 스케일링을 분석하고
/// 예상 생존율을 계산합니다.
void main() {
  group('전체 레벨 밸런스 분석', () {
    test('레벨별 몬스터 vs 플레이어 스탯 비교', () {
      print('\n${'=' * 80}');
      print('레벨별 밸런스 분석 리포트');
      print('${'=' * 80}\n');

      // 분석할 레벨
      final levels = [1, 5, 8, 10, 20, 30, 50, 80, 100];

      print('### 1. 몬스터 스탯 (현재 공식)');
      print('| 레벨 | HP | ATK | DEF | EXP | 타입 |');
      print('|------|-----|-----|-----|-----|------|');
      for (final level in levels) {
        final m = MonsterBaseStats.forLevel(level);
        print(
          '| ${level.toString().padLeft(4)} | ${m.hp.toString().padLeft(4)} '
          '| ${m.atk.toString().padLeft(3)} | ${m.def.toString().padLeft(3)} '
          '| ${m.exp.toString().padLeft(3)} | Normal |',
        );
      }

      print('\n### 2. 플레이어 예상 스탯 (장비 포함)');
      print('| 레벨 | HP | ATK | DEF | 장비DEF |');
      print('|------|-----|-----|-----|---------|');
      for (final level in levels) {
        final player = _estimatePlayerStats(level);
        print(
          '| ${level.toString().padLeft(4)} | ${player.hp.toString().padLeft(4)} '
          '| ${player.atk.toString().padLeft(3)} | ${player.def.toString().padLeft(3)} '
          '| ${player.equipDef.toString().padLeft(7)} |',
        );
      }

      print('\n### 3. 전투 시뮬레이션 (평균 데미지)');
      print('| 레벨 | 몬→플 | 플→몬 | 플생존 | 몬생존 | 승률예상 |');
      print('|------|-------|-------|--------|--------|----------|');
      for (final level in levels) {
        final sim = _simulateCombat(level);
        print(
          '| ${level.toString().padLeft(4)} '
          '| ${sim.monsterDamage.toString().padLeft(5)} '
          '| ${sim.playerDamage.toString().padLeft(5)} '
          '| ${sim.playerHits.toString().padLeft(6)} '
          '| ${sim.monsterHits.toString().padLeft(6)} '
          '| ${(sim.winRate * 100).toStringAsFixed(0).padLeft(8)}% |',
        );
      }

      print('\n### 4. 밸런스 진단');
      for (final level in levels) {
        final sim = _simulateCombat(level);
        final tier = LevelTierSettings.forLevel(level);
        final targetWinRate = 1.0 - tier.targetDeathRate;
        final diagnosis = sim.winRate >= targetWinRate
            ? '✓ 적정'
            : '✗ 조정필요 (목표: ${(targetWinRate * 100).toStringAsFixed(0)}%)';
        print(
          '레벨 $level (${tier.name}): 승률 ${(sim.winRate * 100).toStringAsFixed(0)}% $diagnosis',
        );
      }

      print('\n${'=' * 80}');
    });

    test('문제점 및 개선 제안', () {
      print('\n### 현재 밸런스 문제점\n');

      // 레벨 8 상세 분석 (사용자 보고 케이스)
      final level = 8;
      final monster = MonsterBaseStats.forLevel(level);
      final player = _estimatePlayerStats(level);

      print('#### 레벨 8 상세 분석 (사용자 보고 케이스)');
      print('- 몬스터 ATK: ${monster.atk}');
      print('- 플레이어 HP: ${player.hp}');
      print('- 플레이어 DEF: ${player.def}');

      // 데미지 계산 (combat_calculator 공식)
      // damage = ATK * 0.8~1.2 - DEF * 0.3
      final minDamage = (monster.atk * 0.8 - player.def * 0.3).round();
      final maxDamage = (monster.atk * 1.2 - player.def * 0.3).round();
      print('- 몬스터 데미지: $minDamage ~ $maxDamage');
      print(
        '- 플레이어 생존 히트: ${(player.hp / maxDamage).floor()} ~ ${(player.hp / minDamage).ceil()}',
      );

      print('\n#### 적용된 밸런스 수정');
      print('1. 플레이어 HP 스케일링 상향:');
      print('   - hpPerLevel: 12 → 18 (50% 증가)');
      print('   - hpPerCon: 6 → 10 (67% 증가)');
      print('2. 데미지 공식 DEF 감산율 상향:');
      print('   - defenderDef * 0.3 → defenderDef * 0.5 (방어력 효과 67% 증가)');
      print('3. 몬스터 ATK 대폭 하향:');
      print('   - 5 + level * 6 → 3 + level * 4 (33% 감소)');
    });
  });
}

/// 플레이어 예상 스탯
class _PlayerEstimate {
  final int hp;
  final int atk;
  final int def;
  final int equipDef;

  _PlayerEstimate({
    required this.hp,
    required this.atk,
    required this.def,
    required this.equipDef,
  });
}

/// 레벨별 플레이어 스탯 추정
///
/// 가정:
/// - 평균 스탯: STR/CON/DEX = 15 (3d6 평균 10.5 + 종족/클래스 보정)
/// - 장비: 레벨 * 0.8 수준의 평균 장비
_PlayerEstimate _estimatePlayerStats(int level) {
  // 기본 스탯 (평균)
  const str = 15;
  const con = 15;
  // dex는 회피/크리티컬에 영향, 여기서는 HP/ATK/DEF만 분석

  // 기본 HP (종족별 다르지만 평균 ~10 가정)
  const baseHp = 10;
  // PlayerScaling 공식: hpMax = baseHp + (level - 1) * hpPerLevel + conBonus * hpPerCon
  // 수정: hpPerLevel 12→18, hpPerCon 6→10
  final hpMax = baseHp + (level - 1) * 18 + (con - 10) * 10;

  // 장비 스탯 추정 (레벨 * 0.8 수준의 common 장비 10개)
  final equipLevel = (level * 0.8).round().clamp(1, level);
  final equipBaseValue = (equipLevel * 1.2 * ItemRarity.common.multiplier)
      .round();

  // 무기 ATK (speedMultiplier 1.0 가정)
  final weaponAtk = equipBaseValue;

  // 방어구 DEF (10개 슬롯, 평균 multiplier 0.85)
  final armorDef = (equipBaseValue * 0.85 * 10).round();

  // CombatStats.fromStats 공식
  // baseAtk = effectiveStr * 2 + level + equipStats.atk
  final baseAtk = str * 2 + level + weaponAtk;
  // baseDef = effectiveCon + (level ~/ 2) + equipStats.def
  final baseDef = con + (level ~/ 2) + armorDef;

  return _PlayerEstimate(
    hp: hpMax,
    atk: baseAtk,
    def: baseDef,
    equipDef: armorDef,
  );
}

/// 전투 시뮬레이션 결과
class _CombatSimulation {
  final int monsterDamage;
  final int playerDamage;
  final int playerHits; // 플레이어가 버틸 수 있는 히트 수
  final int monsterHits; // 몬스터를 죽이는데 필요한 히트 수
  final double winRate;

  _CombatSimulation({
    required this.monsterDamage,
    required this.playerDamage,
    required this.playerHits,
    required this.monsterHits,
    required this.winRate,
  });
}

/// 전투 시뮬레이션
_CombatSimulation _simulateCombat(int level) {
  final monster = MonsterBaseStats.forLevel(level);
  final player = _estimatePlayerStats(level);

  // 데미지 계산 (combat_calculator 평균)
  // damage = ATK * 1.0 - DEF * 0.5 (DEF 감산율 상향)
  final monsterDamage = (monster.atk * 1.0 - player.def * 0.5).round().clamp(
    1,
    9999,
  );
  final playerDamage = (player.atk * 1.0 - monster.def * 0.5).round().clamp(
    1,
    9999,
  );

  // 생존 히트 수
  final playerHits = (player.hp / monsterDamage).ceil();
  final monsterHits = (monster.hp / playerDamage).ceil();

  // 승률 추정 (히트 비율 기반)
  // 플레이어가 먼저 공격한다고 가정하면, playerHits > monsterHits면 승리
  final winRate = playerHits > monsterHits
      ? 0.95 // 압도적 유리
      : playerHits == monsterHits
      ? 0.65 // 동등 (선공 이점)
      : (playerHits / monsterHits).clamp(0.2, 0.9);

  return _CombatSimulation(
    monsterDamage: monsterDamage,
    playerDamage: playerDamage,
    playerHits: playerHits,
    monsterHits: monsterHits,
    winRate: winRate,
  );
}
