import 'package:asciineverdie/data/game_text_l10n.dart' as l10n;
import 'package:asciineverdie/src/core/model/monster_grade.dart';
import 'package:asciineverdie/src/core/model/pq_config.dart';
import 'package:asciineverdie/src/core/util/deterministic_random.dart';
import 'package:asciineverdie/src/core/util/pq_random.dart';

/// 몬스터 생성 관련 함수들
/// 원본 Main.pas의 몬스터 생성 로직을 포팅

/// monsterTask의 반환 타입 (원본 fTask.Caption 정보 포함)
class MonsterTaskResult {
  const MonsterTaskResult({
    required this.displayName,
    required this.baseName,
    required this.level,
    required this.part,
    required this.grade,
  });

  /// 화면에 표시할 몬스터 이름 (형용사 포함, 예: "a sick Goblin")
  final String displayName;

  /// 기본 몬스터 이름 (형용사 제외, 예: "Goblin")
  final String baseName;

  /// 몬스터 레벨
  final int level;

  /// 전리품 부위 (예: "claw", "tail", "*"는 WinItem 호출)
  final String part;

  /// 몬스터 등급 (Normal/Elite/Boss)
  final MonsterGrade grade;
}

/// 몬스터 등급 결정 (Normal 85%, Elite 12%, Boss 3%)
/// 몬스터 레벨이 플레이어 레벨보다 높으면 상위 등급 확률 증가
MonsterGrade _determineGrade(
  int monsterLevel,
  int playerLevel,
  DeterministicRandom rng,
) {
  final levelDiff = monsterLevel - playerLevel;
  final eliteBonus = (levelDiff * 2).clamp(0, 10);
  final bossBonus = (levelDiff * 0.5).clamp(0, 3).toInt();

  final roll = rng.nextInt(100);
  if (roll < 3 + bossBonus) return MonsterGrade.boss;
  if (roll < 15 + eliteBonus) return MonsterGrade.elite;
  return MonsterGrade.normal;
}

/// 몬스터 문자열에서 레벨 파싱
int _monsterLevel(String entry) {
  final parts = entry.split('|');
  if (parts.length < 2) return 0;
  return int.tryParse(parts[1]) ?? 0;
}

/// 몬스터 태스크 생성 (원본 Main.pas:523-640)
MonsterTaskResult monsterTask(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  String? questMonster,
  int? questLevel,
) {
  var targetLevel = level;

  for (var i = level; i > 0; i--) {
    if (rng.nextInt(5) < 2) {
      targetLevel += rng.nextInt(2) * 2 - 1; // RandSign
    }
  }
  if (targetLevel < 1) targetLevel = 1;

  String monster;
  int monsterLevel;
  String part;
  bool definite = false;

  // 원본 Main.pas:537-547: 가끔 NPC를 몬스터로 사용
  if (rng.nextInt(25) == 0) {
    final raceEn = pick(config.races, rng).split('|').first;
    final race = l10n.translateRace(raceEn);
    if (rng.nextInt(2) == 0) {
      final klassEn = pick(config.klasses, rng).split('|').first;
      final klass = l10n.translateKlass(klassEn);
      monster = l10n.modifierPassing('$race $klass');
    } else {
      final titleEn = pickLow(config.titles, rng);
      final title = l10n.translateTitle(titleEn);
      monster = l10n.namedMonsterFormat(generateName(rng), '$title $race');
      definite = true;
    }
    monsterLevel = targetLevel;
    part = '*';
  } else if (questMonster != null && rng.nextInt(4) == 0) {
    monster = questMonster;
    final parts = questMonster.split('|');
    monsterLevel = questLevel ?? targetLevel;
    part = parts.length > 2 ? parts[2] : '';
  } else {
    monster = pick(config.monsters, rng);
    monsterLevel = _monsterLevel(monster);
    for (var i = 0; i < 5; i++) {
      final candidate = pick(config.monsters, rng);
      final candLevel = _monsterLevel(candidate);
      if ((targetLevel - candLevel).abs() <
          (targetLevel - monsterLevel).abs()) {
        monster = candidate;
        monsterLevel = candLevel;
      }
    }
    final monsterParts = monster.split('|');
    part = monsterParts.length > 2 ? monsterParts[2] : '';
  }

  final baseName = monster.split('|').first;

  var qty = 1;
  final levelDiff = targetLevel - monsterLevel;
  var name = l10n.translateMonster(baseName);

  if (levelDiff > 10) {
    qty =
        (targetLevel + rng.nextInt(monsterLevel == 0 ? 1 : monsterLevel)) ~/
        (monsterLevel == 0 ? 1 : monsterLevel);
    if (qty < 1) qty = 1;
    targetLevel ~/= qty;
  }

  if (levelDiff <= -10) {
    name = l10n.modifierImaginary(name);
  } else if (levelDiff < -5) {
    final i = 5 - rng.nextInt(10 + levelDiff + 1);
    name = _sick(i, _young((monsterLevel - targetLevel) - i, name));
  } else if (levelDiff < 0) {
    if (rng.nextInt(2) == 1) {
      name = _sick(levelDiff, name);
    } else {
      name = _young(levelDiff, name);
    }
  } else if (levelDiff >= 10) {
    name = l10n.modifierMessianic(name);
  } else if (levelDiff > 5) {
    final i = 5 - rng.nextInt(10 - levelDiff + 1);
    name = _big(i, _special((levelDiff) - i, name));
  } else if (levelDiff > 0) {
    if (rng.nextInt(2) == 1) {
      name = _big(levelDiff, name);
    } else {
      name = _special(levelDiff, name);
    }
  }

  if (!definite) {
    name = l10n.indefiniteL10n(name, qty);
  }

  final grade = _determineGrade(monsterLevel, level, rng);

  return MonsterTaskResult(
    displayName: name,
    baseName: baseName,
    level: monsterLevel * qty,
    part: part,
    grade: grade,
  );
}

/// 이름 있는 몬스터 생성 (NamedMonster, Main.pas:498-512)
String namedMonster(PqConfig config, DeterministicRandom rng, int level) {
  String best = '';
  int bestLevel = 0;

  for (var i = 0; i < 5; i++) {
    final m = pick(config.monsters, rng);
    final parts = m.split('|');
    final name = parts.first;
    final lev = parts.length > 1 ? (int.tryParse(parts[1]) ?? 0) : 0;

    if (best.isEmpty || (level - lev).abs() < (level - bestLevel).abs()) {
      best = name;
      bestLevel = lev;
    }
  }

  final translatedMonster = l10n.translateMonster(best);
  return l10n.namedMonsterFormat(generateName(rng), translatedMonster);
}

// =============================================================================
// 몬스터 수식어 함수들
// =============================================================================

String _sick(int m, String s) {
  switch (m) {
    case -5:
    case 5:
      return l10n.modifierDead(s);
    case -4:
    case 4:
      return l10n.modifierComatose(s);
    case -3:
    case 3:
      return l10n.modifierCrippled(s);
    case -2:
    case 2:
      return l10n.modifierSick(s);
    case -1:
    case 1:
      return l10n.modifierUndernourished(s);
    default:
      return '$m$s';
  }
}

String _young(int m, String s) {
  switch (-m) {
    case -5:
    case 5:
      return l10n.modifierFoetal(s);
    case -4:
    case 4:
      return l10n.modifierBaby(s);
    case -3:
    case 3:
      return l10n.modifierPreadolescent(s);
    case -2:
    case 2:
      return l10n.modifierTeenage(s);
    case -1:
    case 1:
      return l10n.modifierUnderage(s);
    default:
      return '$m$s';
  }
}

String _big(int m, String s) {
  switch (m) {
    case 1:
    case -1:
      return l10n.modifierGreater(s);
    case 2:
    case -2:
      return l10n.modifierMassive(s);
    case 3:
    case -3:
      return l10n.modifierEnormous(s);
    case 4:
    case -4:
      return l10n.modifierGiant(s);
    case 5:
    case -5:
      return l10n.modifierTitanic(s);
    default:
      return s;
  }
}

String _special(int m, String s) {
  switch (-m) {
    case 1:
    case -1:
      return s.contains(' ') ? l10n.modifierVeteran(s) : l10n.modifierBattle(s);
    case 2:
    case -2:
      return l10n.modifierCursed(s);
    case 3:
    case -3:
      return s.contains(' ') ? l10n.modifierWarrior(s) : l10n.modifierWere(s);
    case 4:
    case -4:
      return l10n.modifierUndead(s);
    case 5:
    case -5:
      return l10n.modifierDemon(s);
    default:
      return s;
  }
}
