import 'package:askiineverdie/src/core/model/equipment_item.dart';
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
import 'package:askiineverdie/src/core/model/item_stats.dart';
import 'package:askiineverdie/src/core/util/deterministic_random.dart';

/// 아이템 관리 서비스
///
/// 아이템 생성, 스탯 계산, 무게 관리, 자동 장착 로직을 담당.
/// SRP 준수: 아이템 관련 로직만 처리.
class ItemService {
  const ItemService({required this.rng});

  final DeterministicRandom rng;

  // ============================================================================
  // 무게 시스템
  // ============================================================================

  /// STR 기반 최대 휴대 가능 무게
  ///
  /// 기본 100 + STR당 10
  static int calculateMaxWeight(int str) {
    return 100 + str * 10;
  }

  /// 장비 목록의 총 무게 계산
  static int calculateTotalWeight(List<EquipmentItem> items) {
    return items.fold(0, (sum, item) => sum + item.weight);
  }

  /// 새 아이템 장착 가능 여부 (무게 기준)
  ///
  /// [newItem] 장착하려는 아이템
  /// [currentItems] 현재 장착 중인 아이템 목록
  /// [str] 플레이어 STR
  /// [replacingSlot] 교체할 슬롯 (해당 슬롯 아이템 무게 제외)
  static bool canEquip({
    required EquipmentItem newItem,
    required List<EquipmentItem> currentItems,
    required int str,
    EquipmentSlot? replacingSlot,
  }) {
    final maxWeight = calculateMaxWeight(str);
    var currentWeight = calculateTotalWeight(currentItems);

    // 교체할 슬롯이 있으면 해당 아이템 무게 제외
    if (replacingSlot != null) {
      final existingItem = currentItems
          .where((i) => i.slot == replacingSlot)
          .firstOrNull;
      if (existingItem != null) {
        currentWeight -= existingItem.weight;
      }
    }

    return currentWeight + newItem.weight <= maxWeight;
  }

  // ============================================================================
  // 희귀도 결정
  // ============================================================================

  /// 희귀도 결정 (레벨 기반 확률)
  ///
  /// 레벨이 높을수록 희귀한 아이템 확률 증가
  ItemRarity determineRarity(int level) {
    final roll = rng.nextInt(100);
    final legendaryChance = (level * 0.5).clamp(0, 5).toInt(); // 최대 5%
    final epicChance = (level * 1.0).clamp(0, 10).toInt(); // 최대 10%
    final rareChance = (level * 2.0).clamp(0, 20).toInt(); // 최대 20%
    final uncommonChance = (level * 3.0).clamp(0, 30).toInt(); // 최대 30%

    if (roll < legendaryChance) return ItemRarity.legendary;
    if (roll < legendaryChance + epicChance) return ItemRarity.epic;
    if (roll < legendaryChance + epicChance + rareChance)
      return ItemRarity.rare;
    if (roll < legendaryChance + epicChance + rareChance + uncommonChance) {
      return ItemRarity.uncommon;
    }
    return ItemRarity.common;
  }

  // ============================================================================
  // 아이템 스탯 생성
  // ============================================================================

  /// 아이템 스탯 생성 (레벨/희귀도/슬롯 기반)
  ItemStats generateItemStats({
    required int level,
    required ItemRarity rarity,
    required EquipmentSlot slot,
  }) {
    final baseValue = (level * 2 * rarity.multiplier).round();

    return switch (slot) {
      EquipmentSlot.weapon => _generateWeaponStats(baseValue, rarity),
      EquipmentSlot.shield => _generateShieldStats(baseValue, rarity),
      _ => _generateArmorStats(baseValue, rarity, slot),
    };
  }

  /// 무기 스탯 생성
  ///
  /// 공속(attackSpeed)과 공격력(atk)은 역비례 관계:
  /// - 느린 무기 (1500ms): atk × 1.4
  /// - 기본 무기 (1000ms): atk × 1.0
  /// - 빠른 무기 (600ms): atk × 0.7
  ItemStats _generateWeaponStats(int baseValue, ItemRarity rarity) {
    final criBonus = rarity.index >= ItemRarity.rare.index
        ? 0.02 + rarity.index * 0.01
        : 0.0;
    final parryBonus = rarity.index >= ItemRarity.uncommon.index
        ? 0.01 + rarity.index * 0.005
        : 0.0;

    // 공속 결정 (600ms ~ 1500ms 범위)
    // 희귀도가 높을수록 공속 변동 폭 증가
    final speedVariance =
        300 + rarity.index * 100; // Common: 300, Legendary: 700
    final speedOffset = rng.nextInt(speedVariance * 2) - speedVariance;
    final attackSpeed = (1000 + speedOffset).clamp(600, 1500);

    // 공속-데미지 역비례 계산
    // 기준: 1000ms = 1.0x, 600ms = 0.7x, 1500ms = 1.4x
    final speedMultiplier = 0.3 + (attackSpeed / 1000) * 0.7;
    final adjustedAtk = (baseValue * speedMultiplier).round();

    return ItemStats(
      atk: adjustedAtk,
      criRate: criBonus,
      parryRate: parryBonus,
      attackSpeed: attackSpeed,
    );
  }

  /// 방패 스탯 생성
  ItemStats _generateShieldStats(int baseValue, ItemRarity rarity) {
    final blockBonus = 0.05 + rarity.index * 0.02;

    return ItemStats(def: baseValue ~/ 2, blockRate: blockBonus);
  }

  /// 방어구 스탯 생성
  ItemStats _generateArmorStats(
    int baseValue,
    ItemRarity rarity,
    EquipmentSlot slot,
  ) {
    // 슬롯별 방어력 가중치
    final defMultiplier = switch (slot) {
      EquipmentSlot.hauberk => 1.5, // 갑옷류 최고
      EquipmentSlot.helm => 1.2,
      EquipmentSlot.gambeson => 1.0,
      EquipmentSlot.cuisses => 0.9,
      EquipmentSlot.greaves => 0.8,
      EquipmentSlot.brassairts => 0.7,
      EquipmentSlot.vambraces => 0.7,
      EquipmentSlot.gauntlets => 0.6,
      EquipmentSlot.sollerets => 0.6,
      _ => 0.5,
    };

    final def = (baseValue * defMultiplier).round();

    // 희귀도에 따른 추가 보너스
    final hpBonus = rarity.index >= ItemRarity.rare.index ? baseValue ~/ 2 : 0;
    final evasionBonus = rarity.index >= ItemRarity.epic.index ? 0.01 : 0.0;

    return ItemStats(def: def, hpBonus: hpBonus, evasion: evasionBonus);
  }

  // ============================================================================
  // 아이템 생성
  // ============================================================================

  /// 무게 계산 (레벨/슬롯 기반)
  int calculateWeight({required int level, required EquipmentSlot slot}) {
    // 슬롯별 기본 무게
    final baseWeight = switch (slot) {
      EquipmentSlot.weapon => 10,
      EquipmentSlot.shield => 15,
      EquipmentSlot.helm => 8,
      EquipmentSlot.hauberk => 25,
      EquipmentSlot.brassairts => 6,
      EquipmentSlot.vambraces => 5,
      EquipmentSlot.gauntlets => 4,
      EquipmentSlot.gambeson => 12,
      EquipmentSlot.cuisses => 10,
      EquipmentSlot.greaves => 8,
      EquipmentSlot.sollerets => 6,
    };

    // 레벨에 따라 무게 증가 (고급 아이템일수록 무거움)
    return baseWeight + (level ~/ 5);
  }

  /// 장비 아이템 생성
  ///
  /// [name] 아이템 이름
  /// [slot] 장착 슬롯
  /// [level] 아이템 레벨
  /// [rarity] 희귀도 (null이면 자동 결정)
  EquipmentItem generateEquipment({
    required String name,
    required EquipmentSlot slot,
    required int level,
    ItemRarity? rarity,
  }) {
    final itemRarity = rarity ?? determineRarity(level);
    final stats = generateItemStats(
      level: level,
      rarity: itemRarity,
      slot: slot,
    );
    final weight = calculateWeight(level: level, slot: slot);

    return EquipmentItem(
      name: name,
      slot: slot,
      level: level,
      weight: weight,
      stats: stats,
      rarity: itemRarity,
    );
  }

  // ============================================================================
  // 장비 점수 계산
  // ============================================================================

  /// 장비 점수 계산 (Equipment Score)
  ///
  /// 슬롯별 스탯 가중치를 적용하여 점수 산출.
  /// - 무기: 공격력, 크리티컬, 공속 역비례 반영
  /// - 방어구: 방어력, HP 보너스
  /// - 액세서리: 스탯 보너스
  static int calculateEquipmentScore(EquipmentItem item) {
    var score = 0;
    final stats = item.stats;

    // 공격 스탯 (무기 중심)
    score += stats.atk * 2;
    score += stats.magAtk * 2;
    score += (stats.criRate * 200).round();
    score += (stats.parryRate * 150).round();

    // 방어 스탯
    score += (stats.def * 1.5).round();
    score += (stats.magDef * 1.5).round();
    score += (stats.blockRate * 150).round();
    score += (stats.evasion * 150).round();

    // 자원 스탯
    score += stats.hpBonus;
    score += stats.mpBonus;

    // 능력치 보너스 (가중치 5배)
    score +=
        (stats.strBonus +
            stats.conBonus +
            stats.dexBonus +
            stats.intBonus +
            stats.wisBonus +
            stats.chaBonus) *
        5;

    // 무기 공속 보정 (느린 무기 = 높은 데미지 → 높은 점수)
    // 기준 1000ms, 느린 무기(1500ms)는 +25점, 빠른 무기(600ms)는 -20점
    if (item.slot == EquipmentSlot.weapon && stats.attackSpeed > 0) {
      score += ((stats.attackSpeed - 1000) * 0.05).round();
    }

    // 희귀도 배율 적용
    score = (score * item.rarity.multiplier).round();

    // 레벨 기본 점수
    score += item.level * 5;

    return score;
  }

  // ============================================================================
  // 자동 장착
  // ============================================================================

  /// 새 아이템이 현재 장비보다 좋은지 비교 (점수 기반)
  ///
  /// 장비 점수 기준으로 비교하며, 무게 제한도 고려
  bool shouldEquip({
    required EquipmentItem newItem,
    required EquipmentItem currentItem,
    required List<EquipmentItem> allEquipped,
    required int str,
  }) {
    // 빈 슬롯이면 무조건 장착
    if (currentItem.isEmpty) {
      return canEquip(
        newItem: newItem,
        currentItems: allEquipped,
        str: str,
        replacingSlot: newItem.slot,
      );
    }

    // 점수 비교 (새 아이템이 더 높아야 함)
    final newScore = calculateEquipmentScore(newItem);
    final currentScore = calculateEquipmentScore(currentItem);

    if (newScore <= currentScore) {
      return false;
    }

    // 무게 제한 확인
    return canEquip(
      newItem: newItem,
      currentItems: allEquipped,
      str: str,
      replacingSlot: newItem.slot,
    );
  }
}
