import 'package:flutter/foundation.dart';

import 'package:asciineverdie/data/potion_data.dart';
import 'package:asciineverdie/src/core/model/equipment_item.dart';
import 'package:asciineverdie/src/core/model/equipment_slot.dart';
import 'package:asciineverdie/src/core/model/item_stats.dart';
import 'package:asciineverdie/src/core/model/treasure_chest.dart';
import 'package:asciineverdie/src/core/util/deterministic_random.dart';

/// 보물 상자 서비스
///
/// 상자 내용물 생성 및 오픈 로직 담당
class ChestService {
  ChestService({DeterministicRandom? rng})
    : _rng = rng ?? DeterministicRandom(DateTime.now().millisecondsSinceEpoch);

  final DeterministicRandom _rng;

  // ==========================================================================
  // 상수
  // ==========================================================================

  /// 보상 타입별 확률 (%)
  static const int _equipmentChance = 40; // 장비 40%
  static const int _potionChance = 30; // 포션 30%
  static const int _goldChance = 20; // 골드 20%
  // 경험치 10% (나머지)

  /// 골드 보상 범위 (레벨 * 배율)
  static const int _goldPerLevel = 50;
  static const int _goldVariance = 20;

  /// 경험치 보상 범위 (레벨 * 배율)
  static const int _expPerLevel = 100;
  static const int _expVariance = 30;

  /// 포션 수량 범위
  static const int _minPotionCount = 1;
  static const int _maxPotionCount = 3;

  // ==========================================================================
  // 상자 오픈
  // ==========================================================================

  /// 상자 오픈하여 보상 생성
  ///
  /// [playerLevel] 플레이어 레벨 (보상 스케일링용)
  ChestReward openChest(int playerLevel) {
    final roll = _rng.nextInt(100);

    if (roll < _equipmentChance) {
      // 40%: 장비
      return _generateEquipmentReward(playerLevel);
    } else if (roll < _equipmentChance + _potionChance) {
      // 30%: 포션
      return _generatePotionReward(playerLevel);
    } else if (roll < _equipmentChance + _potionChance + _goldChance) {
      // 20%: 골드
      return _generateGoldReward(playerLevel);
    } else {
      // 10%: 경험치
      return _generateExperienceReward(playerLevel);
    }
  }

  /// 여러 상자 오픈
  List<ChestReward> openMultipleChests(int count, int playerLevel) {
    final rewards = <ChestReward>[];
    for (var i = 0; i < count; i++) {
      rewards.add(openChest(playerLevel));
    }
    return rewards;
  }

  // ==========================================================================
  // 보상 생성
  // ==========================================================================

  /// 장비 보상 생성
  ChestReward _generateEquipmentReward(int playerLevel) {
    // 랜덤 슬롯 선택
    final slotIndex = _rng.nextInt(EquipmentSlot.values.length);
    final slot = EquipmentSlot.values[slotIndex];

    // 희귀도 결정 (상자는 좀 더 좋은 확률)
    final rarity = _rollChestRarity();

    // 아이템 레벨: 플레이어 레벨 ±2
    final minLevel = (playerLevel - 2).clamp(1, 999);
    final maxLevel = playerLevel + 2;
    final itemLevel = minLevel + _rng.nextInt(maxLevel - minLevel + 1);

    // 아이템 생성
    final item = EquipmentItem(
      name: _generateItemName(slot, rarity, itemLevel),
      slot: slot,
      level: itemLevel,
      weight: _calculateWeight(slot, itemLevel),
      stats: _generateItemStats(slot, itemLevel, rarity),
      rarity: rarity,
    );

    debugPrint(
      '[ChestService] Equipment reward: ${item.name} (${rarity.name})',
    );
    return ChestReward.equipment(item);
  }

  /// 포션 보상 생성
  ChestReward _generatePotionReward(int playerLevel) {
    // 레벨에 맞는 티어 선택
    final tier = PotionData.tierForLevel(playerLevel);

    // HP/MP 랜덤 선택
    final isHp = _rng.nextInt(2) == 0;
    final potion = isHp
        ? PotionData.getHpPotionByTier(tier)
        : PotionData.getMpPotionByTier(tier);

    if (potion == null) {
      // 폴백: 기본 포션
      return ChestReward.potion('minor_health_patch', 1);
    }

    // 수량 결정
    final count =
        _minPotionCount + _rng.nextInt(_maxPotionCount - _minPotionCount + 1);

    debugPrint('[ChestService] Potion reward: ${potion.name} x$count');
    return ChestReward.potion(potion.id, count);
  }

  /// 골드 보상 생성
  ChestReward _generateGoldReward(int playerLevel) {
    final baseGold = playerLevel * _goldPerLevel;
    final variance = _rng.nextInt(_goldVariance * 2 + 1) - _goldVariance;
    final gold = (baseGold + (baseGold * variance / 100)).round().clamp(
      10,
      99999,
    );

    debugPrint('[ChestService] Gold reward: $gold');
    return ChestReward.gold(gold);
  }

  /// 경험치 보상 생성
  ChestReward _generateExperienceReward(int playerLevel) {
    final baseExp = playerLevel * _expPerLevel;
    final variance = _rng.nextInt(_expVariance * 2 + 1) - _expVariance;
    final exp = (baseExp + (baseExp * variance / 100)).round().clamp(
      10,
      999999,
    );

    debugPrint('[ChestService] Experience reward: $exp');
    return ChestReward.experience(exp);
  }

  // ==========================================================================
  // 헬퍼 메서드
  // ==========================================================================

  /// 상자 희귀도 롤 (일반 샵보다 좋은 확률)
  /// Common 50%, Uncommon 30%, Rare 15%, Epic 4%, Legendary 1%
  ItemRarity _rollChestRarity() {
    final roll = _rng.nextInt(100);
    if (roll < 50) return ItemRarity.common;
    if (roll < 80) return ItemRarity.uncommon;
    if (roll < 95) return ItemRarity.rare;
    if (roll < 99) return ItemRarity.epic;
    return ItemRarity.legendary;
  }

  /// 아이템 이름 생성
  String _generateItemName(EquipmentSlot slot, ItemRarity rarity, int level) {
    final prefix = _getRarityPrefix(rarity);
    final baseName = _getSlotBaseName(slot);
    final suffix = level > 10 ? ' +${level ~/ 10}' : '';
    return '$prefix$baseName$suffix'.trim();
  }

  String _getRarityPrefix(ItemRarity rarity) {
    return switch (rarity) {
      ItemRarity.common => '',
      ItemRarity.uncommon => 'Fine ',
      ItemRarity.rare => 'Superior ',
      ItemRarity.epic => 'Epic ',
      ItemRarity.legendary => 'Legendary ',
    };
  }

  String _getSlotBaseName(EquipmentSlot slot) {
    return switch (slot) {
      EquipmentSlot.weapon => 'Keyboard',
      EquipmentSlot.shield => 'Firewall Shield',
      EquipmentSlot.helm => 'Neural Headset',
      EquipmentSlot.hauberk => 'Server Rack Armor',
      EquipmentSlot.brassairts => 'Cable Brassairts',
      EquipmentSlot.vambraces => 'USB Vambraces',
      EquipmentSlot.gauntlets => 'Typing Gauntlets',
      EquipmentSlot.gambeson => 'Padded Gambeson',
      EquipmentSlot.cuisses => 'Circuit Cuisses',
      EquipmentSlot.greaves => 'Copper Greaves',
      EquipmentSlot.sollerets => 'Static Boots',
    };
  }

  /// 스탯 생성
  ItemStats _generateItemStats(
    EquipmentSlot slot,
    int level,
    ItemRarity rarity,
  ) {
    final multiplier = rarity.multiplier;
    final baseValue = (level * multiplier).round();

    return switch (slot) {
      EquipmentSlot.weapon => ItemStats(
        atk: baseValue * 2,
        criRate: 0.01 * (level ~/ 5),
        parryRate: 0.005 * level,
      ),
      EquipmentSlot.shield => ItemStats(
        def: baseValue,
        blockRate: 0.02 * (level ~/ 3).clamp(1, 10),
      ),
      EquipmentSlot.helm => ItemStats(
        def: baseValue ~/ 2,
        magDef: baseValue ~/ 2,
        intBonus: level ~/ 10,
      ),
      EquipmentSlot.hauberk => ItemStats(def: baseValue, hpBonus: level * 2),
      EquipmentSlot.brassairts => ItemStats(
        def: baseValue ~/ 2,
        strBonus: level ~/ 15,
      ),
      EquipmentSlot.vambraces => ItemStats(
        def: baseValue ~/ 2,
        dexBonus: level ~/ 15,
      ),
      EquipmentSlot.gauntlets => ItemStats(
        atk: baseValue ~/ 2,
        def: baseValue ~/ 4,
      ),
      EquipmentSlot.gambeson => ItemStats(
        def: baseValue ~/ 2,
        conBonus: level ~/ 15,
      ),
      EquipmentSlot.cuisses => ItemStats(
        def: baseValue ~/ 2,
        evasion: 0.005 * level,
      ),
      EquipmentSlot.greaves => ItemStats(
        def: baseValue ~/ 2,
        evasion: 0.003 * level,
      ),
      EquipmentSlot.sollerets => ItemStats(
        def: baseValue ~/ 3,
        evasion: 0.002 * level,
        dexBonus: level ~/ 20,
      ),
    };
  }

  /// 무게 계산
  int _calculateWeight(EquipmentSlot slot, int level) {
    final baseWeight = switch (slot) {
      EquipmentSlot.weapon => 5,
      EquipmentSlot.shield => 8,
      EquipmentSlot.helm => 4,
      EquipmentSlot.hauberk => 15,
      EquipmentSlot.brassairts => 3,
      EquipmentSlot.vambraces => 3,
      EquipmentSlot.gauntlets => 2,
      EquipmentSlot.gambeson => 6,
      EquipmentSlot.cuisses => 5,
      EquipmentSlot.greaves => 4,
      EquipmentSlot.sollerets => 3,
    };
    return baseWeight + (level ~/ 10);
  }
}
