import 'package:asciineverdie/src/core/engine/shop_service.dart';
import 'package:asciineverdie/src/core/model/equipment_container.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/util/deterministic_random.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  late ShopService service;

  setUp(() {
    // 결정론적 시드(deterministic seed)로 재현 가능한 테스트
    service = ShopService(rng: DeterministicRandom(42));
  });

  // ============================================================================
  // 가격 계산 (price calculation)
  // ============================================================================

  group('calculateBuyPrice', () {
    test('빈 아이템(empty item)은 가격 0', () {
      final emptyItem = EquipmentItem.empty(EquipmentSlot.helm);
      expect(service.calculateBuyPrice(emptyItem), 0);
    });

    test('Common 아이템 가격 = 레벨 * 50 * 1.0', () {
      const item = EquipmentItem(
        name: 'Test Helm',
        slot: EquipmentSlot.helm,
        level: 10,
        weight: 4,
        stats: ItemStats(def: 5),
        rarity: ItemRarity.common,
      );
      // 10 * 50 * 1.0 = 500
      expect(service.calculateBuyPrice(item), 500);
    });

    test('Rare 아이템 가격 = 레벨 * 50 * 5.0', () {
      const item = EquipmentItem(
        name: 'Superior Helm',
        slot: EquipmentSlot.helm,
        level: 10,
        weight: 4,
        stats: ItemStats(def: 10),
        rarity: ItemRarity.rare,
      );
      // 10 * 50 * 5.0 = 2500
      expect(service.calculateBuyPrice(item), 2500);
    });

    test('Legendary 아이템 가격 = 레벨 * 50 * 50.0', () {
      const item = EquipmentItem(
        name: 'Legendary Keyboard',
        slot: EquipmentSlot.weapon,
        level: 5,
        weight: 5,
        stats: ItemStats(atk: 30),
        rarity: ItemRarity.legendary,
      );
      // 5 * 50 * 50.0 = 12500
      expect(service.calculateBuyPrice(item), 12500);
    });
  });

  group('calculateSellPrice', () {
    test('판매 가격 = 구매 가격 * 0.3', () {
      const item = EquipmentItem(
        name: 'Test Shield',
        slot: EquipmentSlot.shield,
        level: 10,
        weight: 8,
        stats: ItemStats(def: 5),
        rarity: ItemRarity.common,
      );
      final buyPrice = service.calculateBuyPrice(item); // 500
      final sellPrice = service.calculateSellPrice(item);
      expect(sellPrice, (buyPrice * 0.3).round());
    });
  });

  // ============================================================================
  // 장비 생성 (item generation)
  // ============================================================================

  group('generateShopItem', () {
    test('생성된 아이템의 슬롯(slot)이 요청과 일치', () {
      final item = service.generateShopItem(
        playerLevel: 10,
        slot: EquipmentSlot.helm,
      );
      expect(item.slot, EquipmentSlot.helm);
      expect(item.isNotEmpty, isTrue);
    });

    test('아이템 레벨은 플레이어 레벨 ±2 범위 이내', () {
      // 여러 시드(seed)로 반복 검증
      for (var seed = 0; seed < 50; seed++) {
        final svc = ShopService(rng: DeterministicRandom(seed));
        final item = svc.generateShopItem(
          playerLevel: 10,
          slot: EquipmentSlot.weapon,
        );
        expect(item.level, inInclusiveRange(8, 12));
      }
    });

    test('targetRarity 지정 시 해당 희귀도로 생성', () {
      final item = service.generateShopItem(
        playerLevel: 5,
        slot: EquipmentSlot.shield,
        targetRarity: ItemRarity.rare,
      );
      expect(item.rarity, ItemRarity.rare);
    });

    test('무기(weapon) 슬롯은 atk 스탯을 가진다', () {
      final item = service.generateShopItem(
        playerLevel: 10,
        slot: EquipmentSlot.weapon,
        targetRarity: ItemRarity.common,
      );
      expect(item.stats.atk, greaterThan(0));
    });

    test('방패(shield) 슬롯은 def 스탯을 가진다', () {
      final item = service.generateShopItem(
        playerLevel: 10,
        slot: EquipmentSlot.shield,
        targetRarity: ItemRarity.common,
      );
      expect(item.stats.def, greaterThan(0));
    });

    test('레벨 1에서도 최소 레벨 1의 아이템 생성', () {
      final item = service.generateShopItem(
        playerLevel: 1,
        slot: EquipmentSlot.helm,
      );
      expect(item.level, greaterThanOrEqualTo(1));
    });
  });

  // ============================================================================
  // buyItem - 단일 구매 (single purchase)
  // ============================================================================

  group('buyItem', () {
    test('골드가 충분하면 구매 성공', () {
      final result = service.buyItem(
        playerLevel: 5,
        currentGold: 100000,
        slot: EquipmentSlot.helm,
      );
      expect(result, isNotNull);
      expect(result!.item.slot, EquipmentSlot.helm);
      expect(result.price, greaterThan(0));
      expect(result.remainingGold, 100000 - result.price);
    });

    test('골드가 부족하면 null 반환', () {
      final result = service.buyItem(
        playerLevel: 50,
        currentGold: 0,
        slot: EquipmentSlot.hauberk,
        preferredRarity: ItemRarity.epic,
      );
      expect(result, isNull);
    });
  });

  // ============================================================================
  // sellItem - 장비 판매 (sell)
  // ============================================================================

  group('sellItem', () {
    test('판매 시 골드가 증가한다', () {
      const item = EquipmentItem(
        name: 'Old Shield',
        slot: EquipmentSlot.shield,
        level: 5,
        weight: 8,
        stats: ItemStats(def: 3),
        rarity: ItemRarity.common,
      );
      final result = service.sellItem(item, 1000);

      expect(result.price, greaterThan(0));
      expect(result.newGold, 1000 + result.price);
      expect(result.item, item);
    });
  });

  // ============================================================================
  // autoBuyForEmptySlots - 빈 슬롯 자동 구매 (auto-buy)
  // ============================================================================

  group('autoBuyForEmptySlots', () {
    test('빈 슬롯이 있으면 자동으로 구매한다', () {
      // 빈 장비(empty equipment)에서 시작
      final emptyEquipment = Equipment.empty();
      final result = service.autoBuyForEmptySlots(
        playerLevel: 5,
        currentGold: 100000,
        currentEquipment: emptyEquipment,
      );

      // 무기(weapon)는 기본 장비가 있으므로 나머지 10개 슬롯 구매 시도
      expect(result.purchasedCount, greaterThan(0));
      expect(result.totalCost, greaterThan(0));
      expect(result.remainingGold, 100000 - result.totalCost);
    });

    test('골드가 0이면 구매하지 않는다', () {
      final emptyEquipment = Equipment.empty();
      final result = service.autoBuyForEmptySlots(
        playerLevel: 5,
        currentGold: 0,
        currentEquipment: emptyEquipment,
      );

      expect(result.purchasedCount, 0);
      expect(result.totalCost, 0);
    });

    test('모든 슬롯이 차있으면 구매하지 않는다', () {
      // 모든 슬롯에 장비가 있는 상태
      final fullEquipment = _createFullEquipment();
      final result = service.autoBuyForEmptySlots(
        playerLevel: 5,
        currentGold: 100000,
        currentEquipment: fullEquipment,
      );

      expect(result.purchasedCount, 0);
      expect(result.totalCost, 0);
    });
  });
}

/// 테스트용 풀 장비 생성 헬퍼
Equipment _createFullEquipment() {
  return Equipment(
    items: [
      EquipmentItem.defaultWeapon(),
      ...List.generate(
        Equipment.slotCount - 1,
        (i) => EquipmentItem(
          name: 'Test Item ${i + 1}',
          slot: EquipmentSlot.values[i + 1],
          level: 5,
          weight: 3,
          stats: const ItemStats(def: 5),
          rarity: ItemRarity.common,
        ),
      ),
    ],
    bestIndex: 0,
  );
}
