import 'dart:math' as math;

import 'package:asciineverdie/data/game_text_l10n.dart' as l10n;
import 'package:asciineverdie/src/core/model/game_state.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_item.dart';
import 'package:asciineverdie/src/core/util/pq_monster.dart';
import 'package:asciineverdie/src/core/util/pq_random.dart';
import 'package:asciineverdie/src/core/util/roman.dart';

/// 퀘스트/Act/시네마틱 관련 함수들
/// 원본 Main.pas의 퀘스트 로직을 포팅

/// 보상 종류
enum RewardKind { spell, equip, stat, item }

/// 퀘스트 결과
class QuestResult {
  const QuestResult({
    required this.caption,
    required this.reward,
    this.monsterName,
    this.monsterLevel,
    this.monsterIndex,
  });

  final String caption;
  final RewardKind reward;

  /// 몬스터 전체 데이터 (예: "Rat|5|tail") - 원본 fQuest.Caption
  final String? monsterName;

  /// 몬스터 레벨 (파싱된 값)
  final int? monsterLevel;

  /// 몬스터 인덱스 (config.monsters에서의 위치) - 원본 fQuest.Tag
  final int? monsterIndex;
}

/// Act 결과
class ActResult {
  const ActResult({
    required this.actTitle,
    required this.plotBarMaxSeconds,
    required this.rewards,
  });

  final String actTitle;
  final int plotBarMaxSeconds;
  final List<RewardKind> rewards;
}

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

/// 퀘스트 완료 처리 (원본 Main.pas:930-984)
QuestResult completeQuest(PqConfig config, DeterministicRandom rng, int level) {
  final rewardRoll = rng.nextInt(4);
  final reward = switch (rewardRoll) {
    0 => RewardKind.spell,
    1 => RewardKind.equip,
    2 => RewardKind.stat,
    _ => RewardKind.item,
  };

  final questRoll = rng.nextInt(5);
  switch (questRoll) {
    case 0:
      // Exterminate: 4번 시도하여 레벨에 가장 가까운 몬스터 선택
      var best = '';
      var bestLevel = 0;
      var bestIndex = 0;
      for (var i = 0; i < 4; i++) {
        final monsterIndex = rng.nextInt(config.monsters.length);
        final m = config.monsters[monsterIndex];
        final l = _monsterLevel(m);
        if (i == 0 || (l - level).abs() < (bestLevel - level).abs()) {
          best = m;
          bestLevel = l;
          bestIndex = monsterIndex;
        }
      }
      final nameEn = best.split('|').first;
      final name = l10n.translateMonster(nameEn);
      return QuestResult(
        caption: l10n.questPatch(l10n.definiteL10n(name, 2)),
        reward: reward,
        monsterName: best,
        monsterLevel: bestLevel,
        monsterIndex: bestIndex,
      );
    case 1:
      // interestingItem: attrib + special 조합 후 번역
      final attr = pick(config.itemAttrib, rng);
      final special = pick(config.specials, rng);
      final item = l10n.translateInterestingItem(attr, special);
      return QuestResult(
        caption: l10n.questLocate(l10n.definiteL10n(item, 1)),
        reward: reward,
      );
    case 2:
      final itemEn = boringItem(config, rng);
      final item = l10n.translateBoringItem(itemEn);
      return QuestResult(caption: l10n.questTransfer(item), reward: reward);
    case 3:
      final itemEn = boringItem(config, rng);
      final item = l10n.translateBoringItem(itemEn);
      return QuestResult(
        caption: l10n.questDownload(l10n.indefiniteL10n(item, 1)),
        reward: reward,
      );
    default:
      // Stabilize: 2번 시도하여 레벨에 가장 가까운 몬스터 선택
      var best = '';
      var bestLevel = 0;
      for (var i = 0; i < 2; i++) {
        final m = pick(config.monsters, rng);
        final l = _monsterLevel(m);
        if (i == 0 || (l - level).abs() < (bestLevel - level).abs()) {
          best = m;
          bestLevel = l;
        }
      }
      final nameEn = best.split('|').first;
      final name = l10n.translateMonster(nameEn);
      return QuestResult(
        caption: l10n.questStabilize(l10n.definiteL10n(name, 2)),
        reward: reward,
      );
  }
}

/// Act별 Plot Bar 최대값 (초) - 10시간 완주 목표
const _actPlotBarSeconds = [
  300, // Prologue: 5분
  7200, // Act I: 2시간
  10800, // Act II: 3시간
  10800, // Act III: 3시간
  5400, // Act IV: 1.5시간
  1800, // Act V: 30분
];

/// Act 완료 처리
ActResult completeAct(int existingActCount) {
  final nextActIndex = existingActCount;
  final title = l10n.actTitle(intToRoman(nextActIndex));
  final plotBarMax = existingActCount < _actPlotBarSeconds.length
      ? _actPlotBarSeconds[existingActCount]
      : 3600;

  final rewards = <RewardKind>[];
  if (existingActCount >= 1) {
    rewards.add(RewardKind.equip);
  }
  if (existingActCount > 1) {
    rewards.add(RewardKind.item);
  }

  return ActResult(
    actTitle: title,
    plotBarMaxSeconds: plotBarMax,
    rewards: rewards,
  );
}

// =============================================================================
// 시네마틱 관련 함수들 (Main.pas:456-521)
// =============================================================================

/// NPC 이름 생성 (ImpressiveGuy, Main.pas:514-521)
String impressiveGuy(PqConfig config, DeterministicRandom rng) {
  final titleEn = pick(config.impressiveTitles, rng);
  final title = l10n.translateImpressiveTitle(titleEn);
  switch (rng.nextInt(2)) {
    case 0:
      final raceEn = pick(config.races, rng).split('|').first;
      final race = l10n.translateRace(raceEn);
      return l10n.impressiveGuyPattern1(title, race);
    case 1:
      final name1 = generateName(rng);
      final name2 = generateName(rng);
      return l10n.impressiveGuyPattern2(title, name1, name2);
    default:
      return title;
  }
}

/// 플롯 간 시네마틱 이벤트 생성 (InterplotCinematic, Main.pas:456-495)
List<QueueEntry> interplotCinematic(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  int plotCount,
) {
  final entries = <QueueEntry>[];

  void q(QueueKind kind, int seconds, String caption) {
    entries.add(
      QueueEntry(kind: kind, durationMillis: seconds * 1000, caption: caption),
    );
  }

  switch (rng.nextInt(3)) {
    case 0:
      // 시나리오 1: 안전한 캐시 영역 도착
      q(QueueKind.task, 1, l10n.cinematicCacheZone1());
      q(QueueKind.task, 2, l10n.cinematicCacheZone2());
      q(QueueKind.task, 2, l10n.cinematicCacheZone3());
      q(QueueKind.task, 1, l10n.cinematicCacheZone4());
      break;

    case 1:
      // 시나리오 2: 강력한 버그와의 전투
      q(QueueKind.task, 1, l10n.cinematicCombat1());
      final nemesis = namedMonster(config, rng, level + 3);
      q(QueueKind.task, 4, l10n.cinematicCombat2(nemesis));

      var s = rng.nextInt(3);
      final combatRounds = rng.nextInt(1 + plotCount);
      for (var i = 0; i < combatRounds; i++) {
        s += 1 + rng.nextInt(2);
        switch (s % 3) {
          case 0:
            q(QueueKind.task, 2, l10n.cinematicCombatLocked(nemesis));
            break;
          case 1:
            q(QueueKind.task, 2, l10n.cinematicCombatCorrupts(nemesis));
            break;
          case 2:
            q(QueueKind.task, 2, l10n.cinematicCombatWorking(nemesis));
            break;
        }
      }

      q(QueueKind.task, 3, l10n.cinematicCombatVictory(nemesis));
      q(QueueKind.task, 2, l10n.cinematicCombatWakeUp());
      break;

    case 2:
      // 시나리오 3: 내부자 위협 발견
      final guy = impressiveGuy(config, rng);
      final itemEn = boringItem(config, rng);
      final item = l10n.translateBoringItem(itemEn);
      q(QueueKind.task, 2, l10n.cinematicBetrayal1(guy));
      q(QueueKind.task, 3, l10n.cinematicBetrayal2(guy));
      q(QueueKind.task, 2, l10n.cinematicBetrayal3(item));
      q(QueueKind.task, 2, l10n.cinematicBetrayal4());
      q(QueueKind.task, 2, l10n.cinematicBetrayal5(guy));
      q(QueueKind.task, 3, l10n.cinematicBetrayal6());
      break;
  }

  q(QueueKind.plot, 2, l10n.taskCompiling);

  return entries;
}

// =============================================================================
// 스펠 관련 함수
// =============================================================================

/// 스펠 획득 (원본 Main.pas:770-774)
String winSpell(
  PqConfig config,
  DeterministicRandom rng,
  int wisdom,
  int level,
) {
  final maxIndex = math.min(wisdom + level, config.spells.length);
  if (maxIndex <= 0) return '';
  final index = randomLow(rng, maxIndex);
  final entry = config.spells[index];
  final parts = entry.split('|');
  final name = parts[0];
  final currentRank = romanToInt(parts.length > 1 ? parts[1] : 'I');
  final nextRank = math.max(1, currentRank + 1);
  return '$name|${intToRoman(nextRank)}';
}
