import 'dart:math' as math;

import 'package:asciineverdie/src/core/model/equipment_slot.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의 아이템 생성 로직을 포팅

/// 장비 생성 결과 (구조화된 데이터로 l10n 지원)
class EquipResult {
  const EquipResult({
    required this.baseName,
    this.modifiers = const [],
    this.plusValue = 0,
  });

  /// 기본 장비 이름 (예: "VPN Cloak")
  final String baseName;

  /// 수식어 목록 (예: ["Holey", "Deprecated"])
  final List<String> modifiers;

  /// +/- 수치 (예: -1, +2)
  final int plusValue;

  /// 영문 전체 이름 생성 (기존 방식)
  String get displayName {
    var name = baseName;
    for (final mod in modifiers) {
      name = '$mod $name';
    }
    if (plusValue != 0) {
      name = '${plusValue > 0 ? '+' : ''}$plusValue $name';
    }
    return name;
  }
}

/// 아이템 생성 결과 (구조화된 데이터로 l10n 지원)
class ItemResult {
  const ItemResult({this.attrib, this.special, this.itemOf, this.boringItem});

  /// 아이템 속성 (예: "Golden")
  final String? attrib;

  /// 특수 아이템 (예: "Iterator")
  final String? special;

  /// "~의" 접미사 (예: "Monitoring")
  final String? itemOf;

  /// 단순 아이템 (보링 아이템용)
  final String? boringItem;

  /// 영문 전체 이름 생성 (기존 방식)
  String get displayName {
    if (boringItem != null) return boringItem!;
    if (attrib != null && special != null && itemOf != null) {
      return '$attrib $special of $itemOf';
    }
    if (attrib != null && special != null) {
      return '$attrib $special';
    }
    return '';
  }
}

// =============================================================================
// 아이템 생성 함수들
// =============================================================================

/// 단순 아이템 (Boring Item)
String boringItem(PqConfig config, DeterministicRandom rng) {
  return pick(config.boringItems, rng);
}

/// 흥미로운 아이템 (Interesting Item)
String interestingItem(PqConfig config, DeterministicRandom rng) {
  final attr = pick(config.itemAttrib, rng);
  final special = pick(config.specials, rng);
  return '$attr $special';
}

/// 특수 아이템 (Special Item)
String specialItem(PqConfig config, DeterministicRandom rng) {
  return '${interestingItem(config, rng)} of ${pick(config.itemOfs, rng)}';
}

/// 구조화된 단순 아이템 결과 반환 (l10n 지원)
ItemResult boringItemStructured(PqConfig config, DeterministicRandom rng) {
  return ItemResult(boringItem: pick(config.boringItems, rng));
}

/// 구조화된 흥미로운 아이템 결과 반환 (l10n 지원)
ItemResult interestingItemStructured(PqConfig config, DeterministicRandom rng) {
  return ItemResult(
    attrib: pick(config.itemAttrib, rng),
    special: pick(config.specials, rng),
  );
}

/// 구조화된 특수 아이템 결과 반환 (l10n 지원)
ItemResult specialItemStructured(PqConfig config, DeterministicRandom rng) {
  return ItemResult(
    attrib: pick(config.itemAttrib, rng),
    special: pick(config.specials, rng),
    itemOf: pick(config.itemOfs, rng),
  );
}

/// 구조화된 승리 아이템 결과 반환 (l10n 지원)
ItemResult winItemStructured(
  PqConfig config,
  DeterministicRandom rng,
  int inventoryCount,
) {
  final threshold = math.max(250, rng.nextInt(999));
  if (inventoryCount > threshold) {
    return const ItemResult(); // 빈 결과
  }
  return specialItemStructured(config, rng);
}

/// 승리 아이템 (문자열 반환)
String winItem(PqConfig config, DeterministicRandom rng, int inventoryCount) {
  final threshold = math.max(250, rng.nextInt(999));
  if (inventoryCount > threshold) return '';
  return specialItem(config, rng);
}

// =============================================================================
// 장비 선택 함수들
// =============================================================================

/// 무기 선택
String pickWeapon(PqConfig config, DeterministicRandom rng, int level) {
  return _lPick(config.weapons, rng, level);
}

/// 방패 선택
String pickShield(PqConfig config, DeterministicRandom rng, int level) {
  return _lPick(config.shields, rng, level);
}

/// 방어구 선택
String pickArmor(PqConfig config, DeterministicRandom rng, int level) {
  return _lPick(config.armors, rng, level);
}

/// 주문 선택
String pickSpell(PqConfig config, DeterministicRandom rng, int goalLevel) {
  return _lPick(config.spells, rng, goalLevel);
}

/// 원본 Main.pas:776-789 LPick: 6회 시도하여 목표 레벨에 가장 가까운 아이템 선택
String _lPick(List<String> items, DeterministicRandom rng, int goal) {
  if (items.isEmpty) return '';
  var result = pick(items, rng);
  var bestLevel = _parseLevel(result);

  for (var i = 0; i < 5; i++) {
    final candidate = pick(items, rng);
    final candLevel = _parseLevel(candidate);
    if ((goal - candLevel).abs() < (goal - bestLevel).abs()) {
      result = candidate;
      bestLevel = candLevel;
    }
  }
  return result;
}

/// 아이템 문자열에서 레벨 파싱
int _parseLevel(String entry) {
  final parts = entry.split('|');
  if (parts.length < 2) return 0;
  return int.tryParse(parts[1].replaceAll('+', '')) ?? 0;
}

// =============================================================================
// 장비 생성 함수들
// =============================================================================

/// 수식어 추가
String addModifier(
  DeterministicRandom rng,
  String baseName,
  List<String> modifiers,
  int plus,
) {
  var name = baseName;
  var remaining = plus;
  var count = 0;

  while (count < 2 && remaining != 0) {
    final modifier = pick(modifiers, rng);
    final parts = modifier.split('|');
    if (parts.isEmpty) break;
    final label = parts[0];
    final qual = parts.length > 1 ? int.tryParse(parts[1]) ?? 0 : 0;
    if (name.contains(label)) break; // avoid repeats
    if (remaining.abs() < qual.abs()) break;
    name = '$label $name';
    remaining -= qual;
    count++;
  }

  if (remaining != 0) {
    name = '${remaining > 0 ? '+' : ''}$remaining $name';
  }
  return name;
}

/// 장비 생성 (원본 Main.pas:791-830 WinEquip)
/// [slotIndex]: 0=Weapon, 1=Shield, 2-10=Armor 계열
String winEquip(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  int slotIndex,
) {
  final bool isWeapon = slotIndex == 0;
  final List<String> items;
  if (slotIndex == 0) {
    items = config.weapons;
  } else if (slotIndex == 1) {
    items = config.shields;
  } else {
    items = config.armors;
  }
  final better = isWeapon ? config.offenseAttrib : config.defenseAttrib;
  final worse = isWeapon ? config.offenseBad : config.defenseBad;

  final base = _lPick(items, rng, level);
  final parts = base.split('|');
  final baseName = parts[0];
  final qual = parts.length > 1
      ? int.tryParse(parts[1].replaceAll('+', '')) ?? 0
      : 0;

  final plus = level - qual;
  final modifierList = plus >= 0 ? better : worse;
  return addModifier(rng, baseName, modifierList, plus);
}

/// EquipmentSlot enum을 사용하는 편의 함수
String winEquipBySlot(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  EquipmentSlot slot,
) {
  return winEquip(config, rng, level, slot.index);
}

/// 구조화된 장비 생성 결과 반환 (l10n 지원)
EquipResult winEquipStructured(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  int slotIndex,
) {
  final bool isWeapon = slotIndex == 0;
  final List<String> items;
  if (slotIndex == 0) {
    items = config.weapons;
  } else if (slotIndex == 1) {
    items = config.shields;
  } else {
    items = config.armors;
  }
  final better = isWeapon ? config.offenseAttrib : config.defenseAttrib;
  final worse = isWeapon ? config.offenseBad : config.defenseBad;

  final base = _lPick(items, rng, level);
  final parts = base.split('|');
  final baseName = parts[0];
  final qual = parts.length > 1
      ? int.tryParse(parts[1].replaceAll('+', '')) ?? 0
      : 0;

  final plus = level - qual;
  final modifierList = plus >= 0 ? better : worse;
  return _addModifierStructured(rng, baseName, modifierList, plus);
}

/// 구조화된 장비 결과 반환 (내부 함수)
EquipResult _addModifierStructured(
  DeterministicRandom rng,
  String baseName,
  List<String> modifiers,
  int plus,
) {
  final collectedModifiers = <String>[];
  var remaining = plus;
  var count = 0;

  while (count < 2 && remaining != 0) {
    final modifier = pick(modifiers, rng);
    final parts = modifier.split('|');
    if (parts.isEmpty) break;
    final label = parts[0];
    final qual = parts.length > 1 ? int.tryParse(parts[1]) ?? 0 : 0;
    if (collectedModifiers.contains(label)) break; // avoid repeats
    if (remaining.abs() < qual.abs()) break;
    collectedModifiers.add(label);
    remaining -= qual;
    count++;
  }

  return EquipResult(
    baseName: baseName,
    modifiers: collectedModifiers,
    plusValue: remaining,
  );
}

/// EquipmentSlot enum을 사용하는 구조화된 버전
EquipResult winEquipBySlotStructured(
  PqConfig config,
  DeterministicRandom rng,
  int level,
  EquipmentSlot slot,
) {
  return winEquipStructured(config, rng, level, slot.index);
}
