import 'dart:collection';

import 'package:asciineverdie/src/core/model/equipment_item.dart';
import 'package:asciineverdie/src/core/model/equipment_slot.dart';
import 'package:asciineverdie/src/core/model/monetization_state.dart';
import 'package:asciineverdie/src/core/model/monster_grade.dart';
import 'package:asciineverdie/src/core/util/deterministic_random.dart';
import 'package:asciineverdie/src/core/model/game_state.dart';

/// 세이브 파일 버전
/// - v2: 장비 이름만 저장 (레거시)
/// - v3: 장비 전체 정보 저장 (level, rarity, stats 포함)
/// - v4: MonetizationState 추가, DeathInfo.lostItem 추가
const int kSaveVersion = 4;

class GameSave {
  GameSave({
    required this.version,
    required this.rngState,
    required this.traits,
    required this.stats,
    required this.inventory,
    required this.equipment,
    required this.skillBook,
    required this.progress,
    required this.queue,
    this.cheatsEnabled = false,
    this.monetization,
  });

  factory GameSave.fromState(
    GameState state, {
    bool cheatsEnabled = false,
    MonetizationState? monetization,
  }) {
    return GameSave(
      version: kSaveVersion,
      rngState: state.rng.state,
      traits: state.traits,
      stats: state.stats,
      inventory: state.inventory,
      equipment: state.equipment,
      skillBook: state.skillBook,
      progress: state.progress,
      queue: state.queue,
      cheatsEnabled: cheatsEnabled,
      monetization: monetization,
    );
  }

  final int version;
  final int rngState;
  final Traits traits;
  final Stats stats;
  final Inventory inventory;
  final Equipment equipment;
  final SkillBook skillBook;
  final ProgressState progress;
  final QueueState queue;
  final bool cheatsEnabled;

  /// 수익화 시스템 상태 (v4+)
  final MonetizationState? monetization;

  Map<String, dynamic> toJson() {
    return {
      'version': version,
      'cheatsEnabled': cheatsEnabled,
      'rng': rngState,
      'traits': {
        'name': traits.name,
        'race': traits.race,
        'klass': traits.klass,
        'level': traits.level,
        'motto': traits.motto,
        'guild': traits.guild,
        'raceId': traits.raceId,
        'classId': traits.classId,
      },
      'stats': {
        'str': stats.str,
        'con': stats.con,
        'dex': stats.dex,
        'int': stats.intelligence,
        'wis': stats.wis,
        'cha': stats.cha,
        'hpMax': stats.hpMax,
        'mpMax': stats.mpMax,
        'hpCurrent': stats.hpCurrent,
        'mpCurrent': stats.mpCurrent,
      },
      'inventory': {
        'gold': inventory.gold,
        'items': inventory.items
            .map((e) => {'name': e.name, 'count': e.count})
            .toList(),
      },
      'equipment': {
        'items': equipment.items.map((e) => e.toJson()).toList(),
        'bestIndex': equipment.bestIndex,
      },
      'skills': skillBook.skills
          .map((e) => {'name': e.name, 'rank': e.rank})
          .toList(),
      'progress': {
        'task': _barToJson(progress.task),
        'quest': _barToJson(progress.quest),
        'plot': _barToJson(progress.plot),
        'exp': _barToJson(progress.exp),
        'encumbrance': _barToJson(progress.encumbrance),
        'taskInfo': {
          'caption': progress.currentTask.caption,
          'type': progress.currentTask.type.name,
          'monsterBaseName': progress.currentTask.monsterBaseName,
          'monsterPart': progress.currentTask.monsterPart,
          'monsterLevel': progress.currentTask.monsterLevel,
          'monsterGrade': progress.currentTask.monsterGrade?.name,
        },
        'plotStages': progress.plotStageCount,
        'questCount': progress.questCount,
        'plotHistory': progress.plotHistory
            .map((e) => {'caption': e.caption, 'complete': e.isComplete})
            .toList(),
        'questHistory': progress.questHistory
            .map((e) => {'caption': e.caption, 'complete': e.isComplete})
            .toList(),
        'questMonster': progress.currentQuestMonster != null
            ? {
                'data': progress.currentQuestMonster!.monsterData,
                'index': progress.currentQuestMonster!.monsterIndex,
              }
            : null,
        'monstersKilled': progress.monstersKilled,
        'deathCount': progress.deathCount,
      },
      'queue': queue.entries
          .map(
            (e) => {
              'kind': e.kind.name,
              'duration': e.durationMillis,
              'caption': e.caption,
              'taskType': e.taskType.name,
            },
          )
          .toList(),
      if (monetization != null) 'monetization': monetization!.toJson(),
    };
  }

  static GameSave fromJson(Map<String, dynamic> json) {
    final traitsJson =
        json['traits'] as Map<String, dynamic>? ?? <String, dynamic>{};
    final statsJson =
        json['stats'] as Map<String, dynamic>? ?? <String, dynamic>{};
    final inventoryJson =
        json['inventory'] as Map<String, dynamic>? ?? <String, dynamic>{};
    final equipmentJson =
        json['equipment'] as Map<String, dynamic>? ?? <String, dynamic>{};
    final progressJson =
        json['progress'] as Map<String, dynamic>? ?? <String, dynamic>{};
    final queueJson = (json['queue'] as List<dynamic>? ?? []).cast<dynamic>();
    final skillsJson = (json['skills'] as List<dynamic>? ?? []).cast<dynamic>();

    return GameSave(
      version: json['version'] as int? ?? kSaveVersion,
      cheatsEnabled: json['cheatsEnabled'] as bool? ?? false,
      rngState: json['rng'] as int? ?? 0,
      traits: Traits(
        name: traitsJson['name'] as String? ?? '',
        race: traitsJson['race'] as String? ?? '',
        klass: traitsJson['klass'] as String? ?? '',
        level: traitsJson['level'] as int? ?? 1,
        motto: traitsJson['motto'] as String? ?? '',
        guild: traitsJson['guild'] as String? ?? '',
        raceId: traitsJson['raceId'] as String? ?? '',
        classId: traitsJson['classId'] as String? ?? '',
      ),
      stats: Stats(
        str: statsJson['str'] as int? ?? 0,
        con: statsJson['con'] as int? ?? 0,
        dex: statsJson['dex'] as int? ?? 0,
        intelligence: statsJson['int'] as int? ?? 0,
        wis: statsJson['wis'] as int? ?? 0,
        cha: statsJson['cha'] as int? ?? 0,
        hpMax: statsJson['hpMax'] as int? ?? 0,
        mpMax: statsJson['mpMax'] as int? ?? 0,
        hpCurrent: statsJson['hpCurrent'] as int?,
        mpCurrent: statsJson['mpCurrent'] as int?,
      ),
      inventory: Inventory(
        gold: inventoryJson['gold'] as int? ?? 0,
        items: (inventoryJson['items'] as List<dynamic>? ?? [])
            .map(
              (e) => InventoryEntry(
                name: (e as Map<String, dynamic>)['name'] as String? ?? '',
                count: (e)['count'] as int? ?? 0,
              ),
            )
            .toList(),
      ),
      equipment: _equipmentFromJson(
        equipmentJson,
        json['version'] as int? ?? 2,
      ),
      skillBook: SkillBook(
        skills: skillsJson
            .map(
              (e) => SkillEntry(
                name: (e as Map<String, dynamic>)['name'] as String? ?? '',
                rank: (e)['rank'] as String? ?? 'I',
              ),
            )
            .toList(),
      ),
      progress: ProgressState(
        task: _barFromJson(progressJson['task'] as Map<String, dynamic>? ?? {}),
        quest: _barFromJson(
          progressJson['quest'] as Map<String, dynamic>? ?? {},
        ),
        plot: _barFromJson(progressJson['plot'] as Map<String, dynamic>? ?? {}),
        exp: _barFromJson(progressJson['exp'] as Map<String, dynamic>? ?? {}),
        encumbrance: _barFromJson(
          progressJson['encumbrance'] as Map<String, dynamic>? ?? {},
        ),
        currentTask: _taskInfoFromJson(
          progressJson['taskInfo'] as Map<String, dynamic>? ??
              <String, dynamic>{},
        ),
        plotStageCount: progressJson['plotStages'] as int? ?? 1,
        questCount: progressJson['questCount'] as int? ?? 0,
        plotHistory: _historyListFromJson(
          progressJson['plotHistory'] as List<dynamic>?,
        ),
        questHistory: _historyListFromJson(
          progressJson['questHistory'] as List<dynamic>?,
        ),
        currentQuestMonster: _questMonsterFromJson(
          progressJson['questMonster'] as Map<String, dynamic>?,
        ),
        monstersKilled: progressJson['monstersKilled'] as int? ?? 0,
        deathCount: progressJson['deathCount'] as int? ?? 0,
      ),
      queue: QueueState(
        entries: Queue<QueueEntry>.from(
          queueJson.map((e) {
            final m = e as Map<String, dynamic>;
            final kind = QueueKind.values.firstWhere(
              (k) => k.name == m['kind'],
              orElse: () => QueueKind.task,
            );
            final taskType = TaskType.values.firstWhere(
              (t) => t.name == m['taskType'],
              orElse: () => TaskType.neutral,
            );
            return QueueEntry(
              kind: kind,
              durationMillis: m['duration'] as int? ?? 0,
              caption: m['caption'] as String? ?? '',
              taskType: taskType,
            );
          }),
        ),
      ),
      monetization: _monetizationFromJson(
        json['monetization'] as Map<String, dynamic>?,
      ),
    );
  }

  GameState toState() {
    return GameState(
      rng: DeterministicRandom.fromState(rngState),
      traits: traits,
      stats: stats,
      inventory: inventory,
      equipment: equipment,
      skillBook: skillBook,
      progress: progress,
      queue: queue,
    );
  }
}

Map<String, dynamic> _barToJson(ProgressBarState bar) => {
  'pos': bar.position,
  'max': bar.max,
};

ProgressBarState _barFromJson(Map<String, dynamic> json) => ProgressBarState(
  position: json['pos'] as int? ?? 0,
  max: json['max'] as int? ?? 1,
);

TaskInfo _taskInfoFromJson(Map<String, dynamic> json) {
  final typeName = json['type'] as String?;
  final type = TaskType.values.firstWhere(
    (t) => t.name == typeName,
    orElse: () => TaskType.neutral,
  );

  // monsterGrade 파싱
  final gradeName = json['monsterGrade'] as String?;
  final monsterGrade = gradeName != null
      ? MonsterGrade.values.firstWhere(
          (g) => g.name == gradeName,
          orElse: () => MonsterGrade.normal,
        )
      : null;

  return TaskInfo(
    caption: json['caption'] as String? ?? '',
    type: type,
    monsterBaseName: json['monsterBaseName'] as String?,
    monsterPart: json['monsterPart'] as String?,
    monsterLevel: json['monsterLevel'] as int?,
    monsterGrade: monsterGrade,
  );
}

List<HistoryEntry> _historyListFromJson(List<dynamic>? json) {
  if (json == null || json.isEmpty) return [];
  return json.map((e) {
    final m = e as Map<String, dynamic>;
    return HistoryEntry(
      caption: m['caption'] as String? ?? '',
      isComplete: m['complete'] as bool? ?? false,
    );
  }).toList();
}

QuestMonsterInfo? _questMonsterFromJson(Map<String, dynamic>? json) {
  if (json == null) return null;
  return QuestMonsterInfo(
    monsterData: json['data'] as String? ?? '',
    monsterIndex: json['index'] as int? ?? -1,
  );
}

/// 장비 데이터 역직렬화 (버전별 분기 처리)
///
/// - v2 이하: 레거시 문자열 기반 (이름만 저장)
/// - v3 이상: 전체 EquipmentItem 정보 저장
Equipment _equipmentFromJson(Map<String, dynamic> json, int version) {
  // v3 이상: 새로운 형식 (items 배열)
  if (version >= 3 && json['items'] != null) {
    final itemsList = json['items'] as List<dynamic>;
    final items = <EquipmentItem>[];

    for (var i = 0; i < Equipment.slotCount; i++) {
      if (i < itemsList.length) {
        final itemJson = itemsList[i] as Map<String, dynamic>;
        items.add(EquipmentItem.fromJson(itemJson));
      } else {
        // 누락된 슬롯은 빈 아이템으로 채움
        items.add(EquipmentItem.empty(EquipmentSlot.values[i]));
      }
    }

    return Equipment(items: items, bestIndex: json['bestIndex'] as int? ?? 0);
  }

  // v2 이하: 레거시 형식 (문자열 기반)
  return Equipment.fromStrings(
    weapon: json['weapon'] as String? ?? 'Keyboard',
    shield: json['shield'] as String? ?? '',
    helm: json['helm'] as String? ?? '',
    hauberk: json['hauberk'] as String? ?? '',
    brassairts: json['brassairts'] as String? ?? '',
    vambraces: json['vambraces'] as String? ?? '',
    gauntlets: json['gauntlets'] as String? ?? '',
    gambeson: json['gambeson'] as String? ?? '',
    cuisses: json['cuisses'] as String? ?? '',
    greaves: json['greaves'] as String? ?? '',
    sollerets: json['sollerets'] as String? ?? '',
    bestIndex: json['bestIndex'] as int? ?? 0,
  );
}

/// MonetizationState 역직렬화 (v4+ 마이그레이션)
///
/// - v3 이하: null (기본값 사용)
/// - v4 이상: 저장된 상태 로드
MonetizationState? _monetizationFromJson(Map<String, dynamic>? json) {
  if (json == null) return null;
  return MonetizationState.fromJson(json);
}
