import 'package:asciineverdie/src/core/engine/stat_calculator.dart';
import 'package:asciineverdie/src/core/model/class_traits.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/race_traits.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  const calculator = StatCalculator();

  group('StatCalculator', () {
    group('applyModifiers', () {
      test('종족 스탯 보정 적용', () {
        final baseStats = const Stats(
          str: 10,
          con: 10,
          dex: 10,
          intelligence: 10,
          wis: 10,
          cha: 10,
          hpMax: 100,
          mpMax: 50,
        );

        // +2 STR, -1 INT 종족
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {StatType.str: 2, StatType.intelligence: -1},
        );

        // 보정 없는 클래스
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.applyModifiers(
          baseStats: baseStats,
          race: race,
          klass: klass,
        );

        expect(result.str, equals(12)); // 10 + 2
        expect(result.intelligence, equals(9)); // 10 - 1
        expect(result.con, equals(10)); // 변화 없음
      });

      test('클래스 스탯 보정 적용', () {
        final baseStats = const Stats(
          str: 10,
          con: 10,
          dex: 10,
          intelligence: 10,
          wis: 10,
          cha: 10,
          hpMax: 100,
          mpMax: 50,
        );

        // 보정 없는 종족
        const race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: {},
        );

        // +3 CON, +1 DEX 클래스
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {StatType.con: 3, StatType.dex: 1},
        );

        final result = calculator.applyModifiers(
          baseStats: baseStats,
          race: race,
          klass: klass,
        );

        expect(result.con, equals(13)); // 10 + 3
        expect(result.dex, equals(11)); // 10 + 1
      });

      test('HP 보너스 패시브 적용 (종족)', () {
        final baseStats = const Stats(
          str: 10,
          con: 10,
          dex: 10,
          intelligence: 10,
          wis: 10,
          cha: 10,
          hpMax: 100,
          mpMax: 50,
        );

        // +20% HP 종족
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {},
          passives: const [
            PassiveAbility(type: PassiveType.hpBonus, value: 0.2),
          ],
        );

        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.applyModifiers(
          baseStats: baseStats,
          race: race,
          klass: klass,
        );

        expect(result.hpMax, equals(120)); // 100 * 1.2
      });

      test('MP 보너스 패시브 적용 (종족)', () {
        final baseStats = const Stats(
          str: 10,
          con: 10,
          dex: 10,
          intelligence: 10,
          wis: 10,
          cha: 10,
          hpMax: 100,
          mpMax: 50,
        );

        // +20% MP 종족
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {},
          passives: const [
            PassiveAbility(type: PassiveType.mpBonus, value: 0.2),
          ],
        );

        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.applyModifiers(
          baseStats: baseStats,
          race: race,
          klass: klass,
        );

        expect(result.mpMax, equals(60)); // 50 * 1.2
      });
    });

    group('applyPassives', () {
      test('크리티컬 보너스 패시브 적용', () {
        final combatStats = CombatStats.empty().copyWith(
          atk: 50,
          def: 20,
          criRate: 0.1,
        );

        // +5% 크리티컬 종족
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {},
          passives: const [
            PassiveAbility(type: PassiveType.criticalBonus, value: 0.05),
          ],
        );

        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.applyPassives(
          combatStats: combatStats,
          race: race,
          klass: klass,
        );

        expect(result.criRate, closeTo(0.15, 0.001)); // 0.1 + 0.05
      });

      test('크리티컬 확률 캡 (0.8) 적용', () {
        final combatStats = CombatStats.empty().copyWith(
          atk: 50,
          def: 20,
          criRate: 0.7,
        );

        // +20% 크리티컬 종족 (합계 0.9 → 캡 0.8)
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {},
          passives: const [
            PassiveAbility(type: PassiveType.criticalBonus, value: 0.2),
          ],
        );

        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.applyPassives(
          combatStats: combatStats,
          race: race,
          klass: klass,
        );

        expect(result.criRate, equals(0.8)); // 캡 적용
      });

      test('회피율 캡 (0.6) 적용', () {
        final combatStats = CombatStats.empty().copyWith(
          atk: 50,
          def: 20,
          evasion: 0.5,
        );

        const race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: {},
        );

        // +15% 회피 클래스 (합계 0.65 → 캡 0.6)
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
          passives: [
            ClassPassive(type: ClassPassiveType.evasionBonus, value: 0.15),
          ],
        );

        final result = calculator.applyPassives(
          combatStats: combatStats,
          race: race,
          klass: klass,
        );

        expect(result.evasion, equals(0.6)); // 캡 적용
      });

      test('물리 공격력 보너스 적용', () {
        final combatStats = CombatStats.empty().copyWith(atk: 100, def: 20);

        const race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: {},
        );

        // +20% 물리 공격 클래스
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
          passives: [
            ClassPassive(
              type: ClassPassiveType.physicalDamageBonus,
              value: 0.2,
            ),
          ],
        );

        final result = calculator.applyPassives(
          combatStats: combatStats,
          race: race,
          klass: klass,
        );

        expect(result.atk, equals(120)); // 100 * 1.2
      });
    });

    group('calculateExpMultiplier', () {
      test('경험치 배율 반환', () {
        final race = RaceTraits(
          raceId: 'test_race',
          name: 'Test Race',
          statModifiers: const {},
          expMultiplier: 1.10, // +10%
        );

        final result = calculator.calculateExpMultiplier(race);

        expect(result, equals(1.10));
      });
    });

    group('calculatePostCombatHeal', () {
      test('전투 후 회복량 계산', () {
        // +5% 전투 후 회복 클래스
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
          passives: [
            ClassPassive(type: ClassPassiveType.postCombatHeal, value: 0.05),
          ],
        );

        final result = calculator.calculatePostCombatHeal(
          klass: klass,
          maxHp: 200,
        );

        expect(result, equals(10)); // 200 * 0.05
      });

      test('패시브 없으면 0 반환', () {
        const klass = ClassTraits(
          classId: 'test_class',
          name: 'Test Class',
          statModifiers: {},
        );

        final result = calculator.calculatePostCombatHeal(
          klass: klass,
          maxHp: 200,
        );

        expect(result, equals(0));
      });
    });
  });
}
