import 'dart:math' as math;

import 'package:asciineverdie/data/potion_data.dart';
import 'package:asciineverdie/src/core/model/monster_grade.dart';
import 'package:asciineverdie/src/core/model/potion.dart';

/// 물약 서비스
///
/// 물약 사용, 자동 사용 알고리즘, 인벤토리 관리
class PotionService {
  const PotionService();

  /// 글로벌 물약 쿨타임 (1배속 기준 3초)
  static const int globalPotionCooldownMs = 3000;

  // ============================================================================
  // 물약 사용 가능 여부
  // ============================================================================

  /// 물약 사용 가능 여부 체크
  ///
  /// [potionId] 물약 ID
  /// [inventory] 물약 인벤토리
  /// Returns: (사용 가능 여부, 실패 사유)
  (bool, PotionUseFailReason?) canUsePotion(
    String potionId,
    PotionInventory inventory,
  ) {
    // 물약 데이터 존재 체크
    final potion = PotionData.getById(potionId);
    if (potion == null) {
      return (false, PotionUseFailReason.potionNotFound);
    }

    // 보유 수량 체크
    if (!inventory.hasPotion(potionId)) {
      return (false, PotionUseFailReason.outOfStock);
    }

    return (true, null);
  }

  // ============================================================================
  // 물약 사용
  // ============================================================================

  /// 물약 사용
  ///
  /// [potionId] 물약 ID
  /// [inventory] 물약 인벤토리
  /// [currentHp] 현재 HP
  /// [maxHp] 최대 HP
  /// [currentMp] 현재 MP
  /// [maxMp] 최대 MP
  /// [healingMultiplier] 회복력 배율 (기본 1.0, 클래스 패시브 적용)
  PotionUseResult usePotion({
    required String potionId,
    required PotionInventory inventory,
    required int currentHp,
    required int maxHp,
    required int currentMp,
    required int maxMp,
    double healingMultiplier = 1.0,
  }) {
    final (canUse, failReason) = canUsePotion(potionId, inventory);
    if (!canUse) {
      return PotionUseResult.failed(failReason!);
    }

    final potion = PotionData.getById(potionId)!;
    int healedAmount = 0;
    int newHp = currentHp;
    int newMp = currentMp;

    if (potion.isHpPotion) {
      // 회복력 보너스 적용 (예: Debugger Paladin +10%)
      final baseHeal = potion.calculateHeal(maxHp);
      healedAmount = (baseHeal * healingMultiplier).round();
      newHp = (currentHp + healedAmount).clamp(0, maxHp);
      healedAmount = newHp - currentHp; // 실제 회복량
    } else if (potion.isMpPotion) {
      // MP 물약에도 회복력 보너스 적용
      final baseHeal = potion.calculateHeal(maxMp);
      healedAmount = (baseHeal * healingMultiplier).round();
      newMp = (currentMp + healedAmount).clamp(0, maxMp);
      healedAmount = newMp - currentMp; // 실제 회복량
    }

    final newInventory = inventory.usePotion(potionId);

    return PotionUseResult(
      success: true,
      potion: potion,
      healedAmount: healedAmount,
      newHp: newHp,
      newMp: newMp,
      newInventory: newInventory,
    );
  }

  // ============================================================================
  // 긴급 물약 자동 사용
  // ============================================================================

  /// 긴급 HP 물약 선택
  ///
  /// 소모된 HP >= 물약 회복량이면 사용할 최적의 물약 선택
  /// [currentHp] 현재 HP
  /// [maxHp] 최대 HP
  /// [inventory] 물약 인벤토리
  /// [playerLevel] 플레이어 레벨 (적정 티어 판단용)
  Potion? selectEmergencyHpPotion({
    required int currentHp,
    required int maxHp,
    required PotionInventory inventory,
    required int playerLevel,
  }) {
    final hpLost = maxHp - currentHp;
    if (hpLost <= 0) return null;

    // 적정 티어 계산
    final targetTier = PotionData.tierForLevel(playerLevel);

    // 적정 티어부터 낮은 티어 순으로 검색
    for (var tier = targetTier; tier >= 1; tier--) {
      final potion = PotionData.getHpPotionByTier(tier);
      if (potion != null && inventory.hasPotion(potion.id)) {
        final healAmount = potion.calculateHeal(maxHp);
        if (hpLost >= healAmount) {
          return potion;
        }
      }
    }

    // 적정 티어 이상도 검색
    for (var tier = targetTier + 1; tier <= 5; tier++) {
      final potion = PotionData.getHpPotionByTier(tier);
      if (potion != null && inventory.hasPotion(potion.id)) {
        final healAmount = potion.calculateHeal(maxHp);
        if (hpLost >= healAmount) {
          return potion;
        }
      }
    }

    return null;
  }

  /// 긴급 MP 물약 선택
  ///
  /// 소모된 MP >= 물약 회복량이면 사용할 최적의 물약 선택
  Potion? selectEmergencyMpPotion({
    required int currentMp,
    required int maxMp,
    required PotionInventory inventory,
    required int playerLevel,
  }) {
    final mpLost = maxMp - currentMp;
    if (mpLost <= 0) return null;

    // 적정 티어 계산
    final targetTier = PotionData.tierForLevel(playerLevel);

    // 적정 티어부터 낮은 티어 순으로 검색
    for (var tier = targetTier; tier >= 1; tier--) {
      final potion = PotionData.getMpPotionByTier(tier);
      if (potion != null && inventory.hasPotion(potion.id)) {
        final healAmount = potion.calculateHeal(maxMp);
        if (mpLost >= healAmount) {
          return potion;
        }
      }
    }

    // 적정 티어 이상도 검색
    for (var tier = targetTier + 1; tier <= 5; tier++) {
      final potion = PotionData.getMpPotionByTier(tier);
      if (potion != null && inventory.hasPotion(potion.id)) {
        final healAmount = potion.calculateHeal(maxMp);
        if (mpLost >= healAmount) {
          return potion;
        }
      }
    }

    return null;
  }

  // ============================================================================
  // 인벤토리 관리
  // ============================================================================

  /// 물약 드랍 추가
  PotionInventory addPotionDrop(
    PotionInventory inventory,
    String potionId, [
    int count = 1,
  ]) {
    return inventory.addPotion(potionId, count);
  }

  // ============================================================================
  // 물약 구매 시스템
  // ============================================================================

  /// 물약 구매 가능 여부 체크
  ///
  /// [potionId] 물약 ID
  /// [gold] 보유 골드
  /// Returns: (구매 가능 여부, 실패 사유)
  (bool, PotionPurchaseFailReason?) canPurchasePotion(
    String potionId,
    int gold,
  ) {
    final potion = PotionData.getById(potionId);
    if (potion == null) {
      return (false, PotionPurchaseFailReason.potionNotFound);
    }

    if (gold < potion.price) {
      return (false, PotionPurchaseFailReason.insufficientGold);
    }

    return (true, null);
  }

  /// 물약 구매
  ///
  /// [potionId] 물약 ID
  /// [inventory] 현재 물약 인벤토리
  /// [gold] 보유 골드
  /// [count] 구매 수량 (기본 1)
  PotionPurchaseResult purchasePotion({
    required String potionId,
    required PotionInventory inventory,
    required int gold,
    int count = 1,
  }) {
    final potion = PotionData.getById(potionId);
    if (potion == null) {
      return PotionPurchaseResult.failed(
        PotionPurchaseFailReason.potionNotFound,
      );
    }

    final totalCost = potion.price * count;
    if (gold < totalCost) {
      return PotionPurchaseResult.failed(
        PotionPurchaseFailReason.insufficientGold,
      );
    }

    final newInventory = inventory.addPotion(potionId, count);
    final newGold = gold - totalCost;

    return PotionPurchaseResult(
      success: true,
      potion: potion,
      quantity: count,
      totalCost: totalCost,
      newGold: newGold,
      newInventory: newInventory,
    );
  }

  /// 레벨에 맞는 물약 자동 구매
  ///
  /// 골드의 일정 비율을 물약 구매에 사용
  /// [playerLevel] 플레이어 레벨
  /// [inventory] 현재 물약 인벤토리
  /// [gold] 보유 골드
  /// [spendRatio] 골드 사용 비율 (기본 20%)
  PotionPurchaseResult autoPurchasePotions({
    required int playerLevel,
    required PotionInventory inventory,
    required int gold,
    double spendRatio = 0.20,
  }) {
    final tier = PotionData.tierForLevel(playerLevel);
    final hpPotion = PotionData.getHpPotionByTier(tier);
    final mpPotion = PotionData.getMpPotionByTier(tier);

    if (hpPotion == null && mpPotion == null) {
      return PotionPurchaseResult.failed(
        PotionPurchaseFailReason.potionNotFound,
      );
    }

    // 사용 가능 골드
    final spendableGold = (gold * spendRatio).floor();
    if (spendableGold <= 0) {
      return PotionPurchaseResult.failed(
        PotionPurchaseFailReason.insufficientGold,
      );
    }

    var currentInventory = inventory;
    var currentGold = gold;
    var totalSpent = 0;
    var hpPurchased = 0;
    var mpPurchased = 0;

    // HP 물약 우선 구매 (60%), MP 물약 (40%)
    final hpBudget = (spendableGold * 0.6).floor();
    final mpBudget = spendableGold - hpBudget;

    // HP 물약 구매
    if (hpPotion != null && hpBudget >= hpPotion.price) {
      final count = hpBudget ~/ hpPotion.price;
      final cost = count * hpPotion.price;
      currentInventory = currentInventory.addPotion(hpPotion.id, count);
      currentGold -= cost;
      totalSpent += cost;
      hpPurchased = count;
    }

    // MP 물약 구매
    if (mpPotion != null && mpBudget >= mpPotion.price) {
      final count = mpBudget ~/ mpPotion.price;
      final cost = count * mpPotion.price;
      currentInventory = currentInventory.addPotion(mpPotion.id, count);
      currentGold -= cost;
      totalSpent += cost;
      mpPurchased = count;
    }

    if (totalSpent == 0) {
      return PotionPurchaseResult.failed(
        PotionPurchaseFailReason.insufficientGold,
      );
    }

    return PotionPurchaseResult(
      success: true,
      potion: hpPotion ?? mpPotion,
      quantity: hpPurchased + mpPurchased,
      totalCost: totalSpent,
      newGold: currentGold,
      newInventory: currentInventory,
    );
  }

  // ============================================================================
  // 물약 드랍 시스템
  // ============================================================================

  /// 기본 물약 드랍 확률 (15%)
  static const double baseDropChance = 0.15;

  /// 레벨당 드랍 확률 증가 (0.5%씩)
  static const double dropChancePerLevel = 0.005;

  /// 최대 드랍 확률 (35%)
  static const double maxDropChance = 0.35;

  /// 물약 드랍 시도
  ///
  /// 전투 승리 시 물약 드랍 여부 결정 및 물약 획득
  /// [playerLevel] 플레이어 레벨 (드랍 확률 및 티어 결정)
  /// [monsterLevel] 몬스터 레벨 (티어 결정에 영향)
  /// [monsterGrade] 몬스터 등급 (드랍 확률 보너스)
  /// [inventory] 현재 물약 인벤토리
  /// [roll] 0~99 범위의 난수 (드랍 확률 판정)
  /// [typeRoll] 0~99 범위의 난수 (HP/MP 결정)
  /// Returns: (업데이트된 인벤토리, 드랍된 물약 또는 null)
  (PotionInventory, Potion?) tryPotionDrop({
    required int playerLevel,
    required int monsterLevel,
    required MonsterGrade monsterGrade,
    required PotionInventory inventory,
    required int roll,
    required int typeRoll,
  }) {
    // 기본 드랍 확률 계산
    var dropChance = (baseDropChance + playerLevel * dropChancePerLevel).clamp(
      baseDropChance,
      maxDropChance,
    );

    // 몬스터 등급 보너스 (Elite +5%, Boss +15%)
    dropChance += monsterGrade.potionDropBonus;

    // 몬스터 레벨 > 플레이어 레벨이면 추가 확률 (+1%/레벨 차이)
    if (monsterLevel > playerLevel) {
      dropChance += (monsterLevel - playerLevel) * 0.01;
    }

    // 최대 확률 제한 (50%)
    dropChance = dropChance.clamp(0.0, 0.5);

    final dropThreshold = (dropChance * 100).round();

    // 드랍 실패
    if (roll >= dropThreshold) {
      return (inventory, null);
    }

    // 물약 타입 결정 (60% HP, 40% MP)
    final isHpPotion = typeRoll < 60;

    // 티어 결정: max(플레이어 레벨, 몬스터 레벨) 기반
    final effectiveLevel = math.max(playerLevel, monsterLevel);
    final tier = PotionData.tierForLevel(effectiveLevel);

    // 물약 선택
    final Potion? potion;
    if (isHpPotion) {
      potion = PotionData.getHpPotionByTier(tier);
    } else {
      potion = PotionData.getMpPotionByTier(tier);
    }

    if (potion == null) {
      return (inventory, null);
    }

    // 인벤토리에 추가
    final updatedInventory = inventory.addPotion(potion.id);
    return (updatedInventory, potion);
  }
}

/// 물약 사용 결과
class PotionUseResult {
  const PotionUseResult({
    required this.success,
    this.potion,
    this.healedAmount = 0,
    this.newHp = 0,
    this.newMp = 0,
    this.newInventory,
    this.failReason,
  });

  /// 성공 여부
  final bool success;

  /// 사용한 물약
  final Potion? potion;

  /// 실제 회복량
  final int healedAmount;

  /// 사용 후 HP
  final int newHp;

  /// 사용 후 MP
  final int newMp;

  /// 업데이트된 인벤토리
  final PotionInventory? newInventory;

  /// 실패 사유
  final PotionUseFailReason? failReason;

  /// 실패 결과 생성
  factory PotionUseResult.failed(PotionUseFailReason reason) {
    return PotionUseResult(success: false, failReason: reason);
  }
}

/// 물약 사용 실패 사유
enum PotionUseFailReason {
  /// 물약 없음 (데이터 없음)
  potionNotFound,

  /// 보유 물약 없음 (재고 부족)
  outOfStock,

  /// 글로벌 쿨타임 중
  onCooldown,
}

/// 물약 구매 결과
class PotionPurchaseResult {
  const PotionPurchaseResult({
    required this.success,
    this.potion,
    this.quantity = 0,
    this.totalCost = 0,
    this.newGold = 0,
    this.newInventory,
    this.failReason,
  });

  /// 성공 여부
  final bool success;

  /// 구매한 물약
  final Potion? potion;

  /// 구매 수량
  final int quantity;

  /// 총 비용
  final int totalCost;

  /// 구매 후 골드
  final int newGold;

  /// 업데이트된 인벤토리
  final PotionInventory? newInventory;

  /// 실패 사유
  final PotionPurchaseFailReason? failReason;

  /// 실패 결과 생성
  factory PotionPurchaseResult.failed(PotionPurchaseFailReason reason) {
    return PotionPurchaseResult(success: false, failReason: reason);
  }
}

/// 물약 구매 실패 사유
enum PotionPurchaseFailReason {
  /// 물약 없음 (데이터 없음)
  potionNotFound,

  /// 골드 부족
  insufficientGold,
}
