import 'package:asciineverdie/src/core/engine/game_mutations.dart';
import 'package:asciineverdie/src/core/engine/progress_service.dart';
import 'package:asciineverdie/src/core/engine/reward_service.dart';
import 'package:asciineverdie/src/core/model/combat_state.dart';
import 'package:asciineverdie/src/core/model/combat_stats.dart';
import 'package:asciineverdie/src/core/model/game_state.dart';
import 'package:asciineverdie/src/core/model/game_statistics.dart';
import 'package:asciineverdie/src/core/model/hall_of_fame.dart';
import 'package:asciineverdie/src/core/model/monetization_state.dart';
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
import 'package:asciineverdie/src/core/model/pq_config.dart';
import 'package:asciineverdie/src/core/storage/hall_of_fame_storage.dart';
import 'package:asciineverdie/src/core/storage/save_manager.dart';
import 'package:asciineverdie/src/core/storage/save_repository.dart';
import 'package:asciineverdie/src/core/storage/save_service.dart';
import 'package:asciineverdie/src/core/storage/statistics_storage.dart';
import 'package:asciineverdie/src/core/util/balance_constants.dart';

export 'package:asciineverdie/src/core/storage/save_repository.dart'
    show SaveOutcome;
export 'package:asciineverdie/src/core/storage/save_service.dart'
    show SaveFileInfo;

/// 테스트용 Fake SaveManager
///
/// 여러 테스트 파일에서 중복되던 Mock을 통합
class FakeSaveManager implements SaveManager {
  final List<GameState> savedStates = [];

  /// 커스텀 로드 동작 설정
  (SaveOutcome, GameState?, bool, MonetizationState?) Function(String?)? onLoad;

  /// 저장 결과 설정 (기본: 성공)
  SaveOutcome saveOutcome = const SaveOutcome.success();

  @override
  Future<SaveOutcome> saveState(
    GameState state, {
    String? fileName,
    bool cheatsEnabled = false,
    MonetizationState? monetization,
  }) async {
    savedStates.add(state);
    return saveOutcome;
  }

  @override
  Future<(SaveOutcome, GameState?, bool, MonetizationState?)> loadState({
    String? fileName,
  }) async {
    if (onLoad != null) {
      return onLoad!(fileName);
    }
    return (const SaveOutcome.success(), null, false, null);
  }

  @override
  Future<List<SaveFileInfo>> listSaves() async => [];

  @override
  Future<SaveOutcome> deleteSave({String? fileName}) async {
    return const SaveOutcome.success();
  }

  @override
  Future<bool> saveExists({String? fileName}) async => false;
}

/// 테스트용 팩토리 클래스
///
/// 테스트에서 자주 사용되는 객체 생성을 중앙화
class MockFactories {
  MockFactories._();

  /// 기본 PqConfig 생성
  static const PqConfig config = PqConfig();

  /// GameMutations 생성
  static GameMutations createMutations([PqConfig? cfg]) {
    return GameMutations(cfg ?? config);
  }

  /// ProgressService 생성
  static ProgressService createProgressService([PqConfig? cfg]) {
    final c = cfg ?? config;
    final mutations = GameMutations(c);
    return ProgressService(
      config: c,
      mutations: mutations,
      rewards: RewardService(mutations, c),
    );
  }

  /// 기본 GameState 생성
  ///
  /// [seed]: 결정론적 랜덤 시드
  /// [level]: 캐릭터 레벨
  static GameState createGameState({int seed = 42, int level = 1}) {
    return GameState.withSeed(seed: seed);
  }

  /// 테스트용 CombatState 생성
  static CombatState createCombat({
    int playerHpMax = 100,
    int playerHpCurrent = 100,
    int monsterHpMax = 50,
    int monsterHpCurrent = 50,
    int monsterLevel = 1,
    String monsterName = 'Test Monster',
  }) {
    final playerStats = CombatStats.empty().copyWith(
      hpMax: playerHpMax,
      hpCurrent: playerHpCurrent,
      mpMax: 50,
      mpCurrent: 50,
      atk: 20,
      def: 10,
      attackDelayMs: 1000,
    );

    final monsterStats = MonsterCombatStats(
      name: monsterName,
      level: monsterLevel,
      atk: 10,
      def: 5,
      magDef: 5,
      hpMax: monsterHpMax,
      hpCurrent: monsterHpCurrent,
      criRate: 0.05,
      criDamage: 1.5,
      evasion: 0.0,
      accuracy: 0.8,
      attackDelayMs: 1000,
      expReward: 100,
    );

    return CombatState(
      playerStats: playerStats,
      monsterStats: monsterStats,
      playerAttackAccumulatorMs: 0,
      monsterAttackAccumulatorMs: 0,
      totalDamageDealt: 0,
      totalDamageTaken: 0,
      turnsElapsed: 0,
      isActive: true,
    );
  }

  /// 테스트용 MonsterCombatStats 생성
  static MonsterCombatStats createMonsterStats({
    String name = 'Test Monster',
    int level = 1,
    int atk = 10,
    int def = 5,
    int magDef = 5,
    int hpMax = 100,
    int? hpCurrent,
    double criRate = 0.05,
    double criDamage = 1.5,
    double evasion = 0.0,
    double accuracy = 0.8,
    int attackDelayMs = 1000,
    int expReward = 100,
  }) {
    return MonsterCombatStats(
      name: name,
      level: level,
      atk: atk,
      def: def,
      magDef: magDef,
      hpMax: hpMax,
      hpCurrent: hpCurrent ?? hpMax,
      criRate: criRate,
      criDamage: criDamage,
      evasion: evasion,
      accuracy: accuracy,
      attackDelayMs: attackDelayMs,
      expReward: expReward,
    );
  }

  /// 밸런스 상수 기반 몬스터 스탯 생성
  static MonsterCombatStats createBalancedMonsterStats({
    required int level,
    MonsterType type = MonsterType.normal,
  }) {
    final base = MonsterBaseStats.generate(level, type);
    return MonsterCombatStats(
      name: 'Balanced Monster Lv$level',
      level: level,
      atk: base.atk,
      def: base.def,
      magDef: base.def, // 물리 방어와 동일
      hpMax: base.hp,
      hpCurrent: base.hp,
      criRate: 0.05,
      criDamage: 1.5,
      evasion: 0.0,
      accuracy: 0.8,
      attackDelayMs: 1000,
      expReward: base.exp,
    );
  }
}

/// 테스트용 Fake HallOfFameStorage
///
/// 파일 시스템 접근 없이 메모리에서 동작
class FakeHallOfFameStorage extends HallOfFameStorage {
  HallOfFame _hallOfFame = HallOfFame.empty();

  @override
  Future<HallOfFame> load() async => _hallOfFame;

  @override
  Future<bool> save(HallOfFame hallOfFame) async {
    _hallOfFame = hallOfFame;
    return true;
  }

  @override
  Future<bool> addEntry(HallOfFameEntry entry) async {
    _hallOfFame = _hallOfFame.addEntry(entry);
    return true;
  }

  @override
  Future<bool> deleteEntry(String id) async {
    _hallOfFame = _hallOfFame.removeEntry(id);
    return true;
  }

  @override
  Future<bool> clear() async {
    _hallOfFame = HallOfFame.empty();
    return true;
  }
}

/// 테스트용 Fake StatisticsStorage
///
/// 파일 시스템 접근 없이 메모리에서 동작
class FakeStatisticsStorage extends StatisticsStorage {
  CumulativeStatistics _stats = CumulativeStatistics.empty();

  @override
  Future<CumulativeStatistics> loadCumulative() async => _stats;

  @override
  Future<bool> saveCumulative(CumulativeStatistics stats) async {
    _stats = stats;
    return true;
  }

  @override
  Future<bool> mergeSession(SessionStatistics session) async {
    _stats = _stats.mergeSession(session);
    return true;
  }

  @override
  Future<bool> updateHighestLevel(int level) async {
    if (level <= _stats.highestLevel) return true;
    _stats = _stats.updateHighestLevel(level);
    return true;
  }

  @override
  Future<bool> updateHighestGold(int gold) async {
    if (gold <= _stats.highestGoldHeld) return true;
    _stats = _stats.updateHighestGold(gold);
    return true;
  }

  @override
  Future<bool> recordGameStart() async {
    _stats = _stats.recordGameStart();
    return true;
  }

  @override
  Future<bool> recordGameComplete() async {
    _stats = _stats.recordGameComplete();
    return true;
  }

  @override
  Future<bool> clear() async {
    _stats = CumulativeStatistics.empty();
    return true;
  }
}
