/// 밸런스 상수 정의 (balance constants)
///
/// Phase 6: 레벨 1-100 구간의 난이도 곡선 및 스케일링 상수
library;

/// 경험치 관련 상수 (experience constants)
class ExpConstants {
  ExpConstants._();

  /// 레벨업에 필요한 경험치 계산 (몬스터 기반)
  ///
  /// 공식: (10 + level * 5) * (25 + level / 3)
  /// - 몬스터 경험치와 동기화 (MonsterBaseStats.exp = 10 + level * 5)
  /// - 레벨당 약 25~58마리 처치 필요
  ///
  /// 예상:
  /// 레벨 1: 15 * 25 = 375 exp (~25마리)
  /// 레벨 10: 60 * 28 = 1,680 exp (~28마리)
  /// 레벨 30: 160 * 35 = 5,600 exp (~35마리)
  /// 레벨 50: 260 * 42 = 10,920 exp (~42마리)
  /// 레벨 80: 410 * 52 = 21,320 exp (~52마리)
  /// 레벨 100: 510 * 58 = 29,580 exp (~58마리)
  static int requiredExp(int level) {
    if (level <= 0) return 375;

    // 해당 레벨 몬스터 경험치 = 10 + level * 5
    final monsterExp = 10 + level * 5;
    // 필요 킬 수 = 25 + level / 3 (레벨이 올라갈수록 약간 더 많이)
    final killsRequired = 25 + level ~/ 3;
    return monsterExp * killsRequired;
  }

  /// 총 누적 경험치 계산 (특정 레벨까지)
  static int totalExpToLevel(int level) {
    int total = 0;
    for (int i = 1; i < level; i++) {
      total += requiredExp(i);
    }
    return total;
  }
}

/// 몬스터 타입 (monster type)
enum MonsterType {
  /// 일반 몬스터
  normal,

  /// 정예 몬스터 (Elite)
  elite,

  /// 미니보스
  miniboss,

  /// 보스
  boss,

  /// 최종 보스
  finalBoss,
}

/// 몬스터 타입별 배율 (monster type multipliers)
class MonsterTypeMultiplier {
  const MonsterTypeMultiplier({
    required this.hp,
    required this.atk,
    required this.def,
    required this.exp,
    required this.gold,
  });

  final double hp;
  final double atk;
  final double def;
  final double exp;
  final double gold;

  /// 타입별 배율 가져오기
  static MonsterTypeMultiplier forType(MonsterType type) {
    return switch (type) {
      MonsterType.normal => normal,
      MonsterType.elite => elite,
      MonsterType.miniboss => miniboss,
      MonsterType.boss => boss,
      MonsterType.finalBoss => finalBoss,
    };
  }

  /// 일반: 모든 스탯 1.0배
  static const normal = MonsterTypeMultiplier(
    hp: 1.0,
    atk: 1.0,
    def: 1.0,
    exp: 1.0,
    gold: 1.0,
  );

  /// 정예: HP 2배, ATK 1.3배, DEF 1.2배, EXP 3배 (상향), GOLD 2.5배
  static const elite = MonsterTypeMultiplier(
    hp: 2.0,
    atk: 1.3,
    def: 1.2,
    exp: 3.0, // 2.0 → 3.0 상향
    gold: 2.5,
  );

  /// 미니보스: HP 5배, ATK/DEF 1.5배, EXP 8배 (상향), GOLD 6배
  static const miniboss = MonsterTypeMultiplier(
    hp: 5.0,
    atk: 1.5,
    def: 1.5,
    exp: 8.0, // 5.0 → 8.0 상향
    gold: 6.0,
  );

  /// 보스: HP 8배 (하향), ATK/DEF 1.8배 (하향), EXP 25배 (상향), GOLD 15배
  static const boss = MonsterTypeMultiplier(
    hp: 8.0, // 10.0 → 8.0 하향 (플레이어 접근성 개선)
    atk: 1.8, // 2.0 → 1.8 하향
    def: 1.8, // 2.0 → 1.8 하향
    exp: 25.0, // 15.0 → 25.0 상향
    gold: 15.0,
  );

  /// 최종 보스: HP 12배 (하향), ATK/DEF 2.2배 (하향), EXP 80배 (상향), GOLD 50배
  static const finalBoss = MonsterTypeMultiplier(
    hp: 12.0, // 20.0 → 12.0 대폭 하향 (클리어 가능성 확보)
    atk: 2.2, // 2.5 → 2.2 하향
    def: 2.2, // 2.5 → 2.2 하향
    exp: 80.0, // 50.0 → 80.0 상향
    gold: 50.0,
  );
}

/// 몬스터 기본 스탯 (monster base stats)
class MonsterBaseStats {
  const MonsterBaseStats({
    required this.hp,
    required this.atk,
    required this.def,
    required this.exp,
    required this.gold,
  });

  final int hp;
  final int atk;
  final int def;
  final int exp;
  final int gold;

  /// 레벨 기반 기본 스탯 생성
  ///
  /// HP: 50 + level * 20 + (level^2 / 5)
  /// ATK: 레벨별 차등 적용
  ///      - 레벨 1~5: 2 + level * 3 (초반 난이도 완화)
  ///      - 레벨 6+: 3 + level * 4 (기존 공식)
  ///      - DEF 감산율 0.5와 연동하여 밸런스 조정
  ///      - 플레이어가 5~10회 공격 생존 가능하도록 설계
  /// DEF: 2 + level * 2
  /// EXP: 10 + level * 5
  /// GOLD: 5 + level * 3
  factory MonsterBaseStats.forLevel(int level) {
    // 레벨 1~5: 초반 난이도 완화 (2 + level * 3)
    // 레벨 1=5, 2=8, 3=11, 4=14, 5=17
    // 레벨 6+: 기존 공식 (3 + level * 4)
    // 레벨 6=27, 10=43, 20=83, 50=203, 100=403
    final atk = level <= 5 ? 2 + level * 3 : 3 + level * 4;

    return MonsterBaseStats(
      hp: 50 + level * 20 + (level * level ~/ 5),
      atk: atk,
      def: 2 + level * 2,
      exp: 10 + level * 5,
      gold: 5 + level * 3,
    );
  }

  /// 타입 배율 적용
  MonsterBaseStats applyType(MonsterType type) {
    final mult = MonsterTypeMultiplier.forType(type);
    return MonsterBaseStats(
      hp: (hp * mult.hp).round(),
      atk: (atk * mult.atk).round(),
      def: (def * mult.def).round(),
      exp: (exp * mult.exp).round(),
      gold: (gold * mult.gold).round(),
    );
  }

  /// 레벨과 타입을 기반으로 몬스터 스탯 생성
  static MonsterBaseStats generate(int level, MonsterType type) {
    return MonsterBaseStats.forLevel(level).applyType(type);
  }
}

/// 보스 특수 능력 타입 (boss ability type)
enum BossAbilityType {
  /// 연속 공격 (Syntax Error Dragon)
  multiAttack,

  /// HP 회복 (Memory Leak Hydra)
  regeneration,

  /// 보호막 (Buffer Overflow Titan)
  shield,

  /// 스턴 공격 (Kernel Panic Archon)
  stunAttack,

  /// 페이즈 전환 (Glitch God)
  phaseShift,
}

/// 보스 스탯 (boss stats)
class BossStats extends MonsterBaseStats {
  const BossStats({
    required super.hp,
    required super.atk,
    required super.def,
    required super.exp,
    required super.gold,
    required this.phases,
    required this.enrageThreshold,
    required this.enrageMultiplier,
    required this.hasShield,
    required this.shieldAmount,
    required this.abilities,
  });

  /// 페이즈 수 (글리치 신은 5페이즈)
  final int phases;

  /// 분노 발동 HP % (0.3 = 30%)
  final double enrageThreshold;

  /// 분노 시 스탯 배율
  final double enrageMultiplier;

  /// 보호막 보유 여부
  final bool hasShield;

  /// 보호막 수치
  final int shieldAmount;

  /// 특수 능력 목록
  final List<BossAbilityType> abilities;

  /// Syntax Error Dragon (Act I 보스, 레벨 20)
  static BossStats syntaxErrorDragon(int baseLevel) {
    final base = MonsterBaseStats.generate(baseLevel, MonsterType.boss);
    return BossStats(
      hp: base.hp,
      atk: base.atk,
      def: base.def,
      exp: base.exp,
      gold: base.gold,
      phases: 3,
      enrageThreshold: 0.2,
      enrageMultiplier: 1.5,
      hasShield: false,
      shieldAmount: 0,
      abilities: [BossAbilityType.multiAttack],
    );
  }

  /// Memory Leak Hydra (Act II 보스, 레벨 40)
  static BossStats memoryLeakHydra(int baseLevel) {
    final base = MonsterBaseStats.generate(baseLevel, MonsterType.boss);
    return BossStats(
      hp: base.hp,
      atk: base.atk,
      def: base.def,
      exp: base.exp,
      gold: base.gold,
      phases: 2,
      enrageThreshold: 0.3,
      enrageMultiplier: 1.3,
      hasShield: false,
      shieldAmount: 0,
      abilities: [BossAbilityType.regeneration],
    );
  }

  /// Buffer Overflow Titan (Act III 보스, 레벨 60)
  static BossStats bufferOverflowTitan(int baseLevel) {
    final base = MonsterBaseStats.generate(baseLevel, MonsterType.boss);
    return BossStats(
      hp: base.hp,
      atk: base.atk,
      def: base.def,
      exp: base.exp,
      gold: base.gold,
      phases: 2,
      enrageThreshold: 0.25,
      enrageMultiplier: 1.4,
      hasShield: true,
      shieldAmount: (base.hp * 0.3).round(),
      abilities: [BossAbilityType.shield],
    );
  }

  /// Kernel Panic Archon (Act IV 보스, 레벨 80)
  ///
  /// Phase 6 밸런스 조정: enrageMultiplier 1.6 → 1.5
  static BossStats kernelPanicArchon(int baseLevel) {
    final base = MonsterBaseStats.generate(baseLevel, MonsterType.boss);
    return BossStats(
      hp: base.hp,
      atk: base.atk,
      def: base.def,
      exp: base.exp,
      gold: base.gold,
      phases: 3,
      enrageThreshold: 0.2,
      enrageMultiplier: 1.5, // 1.6 → 1.5 (분노 시 50% 스탯 증가)
      hasShield: true,
      shieldAmount: (base.hp * 0.2).round(),
      abilities: [BossAbilityType.stunAttack],
    );
  }

  /// Glitch God (최종 보스, 레벨 100)
  ///
  /// Phase 6 밸런스 조정:
  /// - enrageThreshold: 0.1 → 0.15 (분노 발동 시점 완화)
  /// - enrageMultiplier: 2.0 → 1.7 (분노 시 스탯 증가 완화)
  /// - shieldAmount: 50% → 35% (보호막 감소)
  static BossStats glitchGod(int baseLevel) {
    final base = MonsterBaseStats.generate(baseLevel, MonsterType.finalBoss);
    return BossStats(
      hp: base.hp,
      atk: base.atk,
      def: base.def,
      exp: base.exp,
      gold: base.gold,
      phases: 5,
      enrageThreshold: 0.15, // 0.1 → 0.15 (15% HP에서 분노)
      enrageMultiplier: 1.7, // 2.0 → 1.7 (분노 시 70% 스탯 증가)
      hasShield: true,
      shieldAmount: (base.hp * 0.35).round(), // 0.5 → 0.35 (보호막 30% 감소)
      abilities: [
        BossAbilityType.phaseShift,
        BossAbilityType.multiAttack,
        BossAbilityType.regeneration,
        BossAbilityType.stunAttack,
      ],
    );
  }
}

/// 레벨 구간별 설정 (level tier settings)
class LevelTierSettings {
  const LevelTierSettings({
    required this.minLevel,
    required this.maxLevel,
    required this.name,
    required this.targetDeathRate,
    required this.estimatedPlayTimeMinutes,
  });

  final int minLevel;
  final int maxLevel;
  final String name;

  /// 목표 사망 확률 (전투당, 0.01 = 1%)
  final double targetDeathRate;

  /// 예상 플레이 시간 (분)
  final int estimatedPlayTimeMinutes;

  /// 초반 (레벨 1-20): 튜토리얼
  static const early = LevelTierSettings(
    minLevel: 1,
    maxLevel: 20,
    name: '초반',
    targetDeathRate: 0.02, // 1-3%
    estimatedPlayTimeMinutes: 90, // 1-2시간
  );

  /// 중반 (레벨 21-50): 본격적인 성장
  static const mid = LevelTierSettings(
    minLevel: 21,
    maxLevel: 50,
    name: '중반',
    targetDeathRate: 0.04, // 3-5%
    estimatedPlayTimeMinutes: 240, // 3-5시간
  );

  /// 후반 (레벨 51-80): 고급 장비
  static const late = LevelTierSettings(
    minLevel: 51,
    maxLevel: 80,
    name: '후반',
    targetDeathRate: 0.075, // 5-10%
    estimatedPlayTimeMinutes: 390, // 5-8시간
  );

  /// 엔드게임 (레벨 81-100): 최종 보스
  static const endgame = LevelTierSettings(
    minLevel: 81,
    maxLevel: 100,
    name: '엔드게임',
    targetDeathRate: 0.15, // 10-20%
    estimatedPlayTimeMinutes: 240, // 3-5시간
  );

  /// 모든 레벨 구간
  static const all = [early, mid, late, endgame];

  /// 레벨로 구간 찾기
  static LevelTierSettings forLevel(int level) {
    for (final tier in all) {
      if (level >= tier.minLevel && level <= tier.maxLevel) {
        return tier;
      }
    }
    return endgame;
  }
}

/// Act별 최소 몬스터 레벨 (act minimum monster level)
///
/// 플레이어 레벨과 무관하게 각 Act에서 등장하는 몬스터의 최소 레벨.
/// 저레벨 플레이어가 고Act에 도달해도 적절한 난이도 유지.
class ActMonsterLevel {
  ActMonsterLevel._();

  /// plotStageCount 기준 최소 몬스터 레벨
  /// - 1: Prologue → 1
  /// - 2: Act I → 3
  /// - 3: Act II → 22
  /// - 4: Act III → 45
  /// - 5: Act IV → 72
  /// - 6: Act V → 88
  static const List<int> _minimumLevels = [
    1, // index 0: unused (plotStageCount starts at 1)
    1, // Prologue (plotStageCount = 1)
    3, // Act I (plotStageCount = 2)
    22, // Act II (plotStageCount = 3)
    45, // Act III (plotStageCount = 4)
    72, // Act IV (plotStageCount = 5)
    88, // Act V (plotStageCount = 6)
  ];

  /// plotStageCount에 해당하는 최소 몬스터 레벨 반환
  static int forPlotStage(int plotStageCount) {
    if (plotStageCount < 1) return 1;
    if (plotStageCount >= _minimumLevels.length) {
      return _minimumLevels.last;
    }
    return _minimumLevels[plotStageCount];
  }
}

/// 플레이어 스탯 스케일링 (player stat scaling)
class PlayerScaling {
  PlayerScaling._();

  /// 레벨당 HP 증가량 (12 → 18 상향, 생존율 개선)
  static const int hpPerLevel = 18;

  /// 레벨당 MP 증가량 (5 → 6 상향)
  static const int mpPerLevel = 6;

  /// CON당 HP 보너스 (6 → 10 상향, 체력 투자 효율 개선)
  static const int hpPerCon = 10;

  /// INT당 MP 보너스 (3 → 4 상향)
  static const int mpPerInt = 4;

  /// 레벨업 시 HP/MP 계산
  static ({int hpMax, int mpMax}) calculateResources({
    required int level,
    required int baseHp,
    required int baseMp,
    required int conBonus,
    required int intBonus,
  }) {
    final hpMax = baseHp + (level - 1) * hpPerLevel + conBonus * hpPerCon;
    final mpMax = baseMp + (level - 1) * mpPerLevel + intBonus * mpPerInt;
    return (hpMax: hpMax, mpMax: mpMax);
  }

  /// 레벨 구간별 ATK 보너스 (후반 DPS 보조)
  /// - 레벨 60+: +1 ATK per level
  /// - 레벨 80+: +2 ATK per level
  static int bonusAtk(int level) {
    if (level >= 80) return (level - 80) * 2 + 20;
    if (level >= 60) return level - 60;
    return 0;
  }
}
