import 'package:asciineverdie/src/core/engine/item_service.dart';
import 'package:asciineverdie/src/core/model/combat_stats.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/game_state.dart';

/// 명예의 전당 엔트리 (Phase 10: Hall of Fame Entry)
///
/// 게임 클리어 시 저장되는 캐릭터 정보
class HallOfFameEntry {
  const HallOfFameEntry({
    required this.id,
    required this.characterName,
    required this.race,
    required this.klass,
    required this.level,
    required this.totalPlayTimeMs,
    required this.totalDeaths,
    required this.monstersKilled,
    required this.questsCompleted,
    required this.clearedAt,
    this.raceId = '',
    this.finalStats,
    this.finalEquipment,
    this.finalSkills,
  });

  /// 고유 ID (UUID)
  final String id;

  /// 캐릭터 이름
  final String characterName;

  /// 종족 (표시용 이름)
  final String race;

  /// 종족 ID (ASCII 캐릭터 프레임용)
  final String raceId;

  /// 클래스
  final String klass;

  /// 최종 레벨
  final int level;

  /// 총 플레이 시간 (밀리초)
  final int totalPlayTimeMs;

  /// 총 사망 횟수
  final int totalDeaths;

  /// 처치한 몬스터 수
  final int monstersKilled;

  /// 완료한 퀘스트 수
  final int questsCompleted;

  /// 클리어 일시
  final DateTime clearedAt;

  /// 최종 전투 스탯 (향후 아스키 아레나용)
  final CombatStats? finalStats;

  /// 최종 장비 목록 (풀 스탯 포함)
  final List<EquipmentItem>? finalEquipment;

  /// 최종 스펠북 (스펠 이름 + 랭크)
  final List<Map<String, String>>? finalSkills;

  /// 플레이 시간을 Duration으로 변환
  Duration get totalPlayTime => Duration(milliseconds: totalPlayTimeMs);

  /// 플레이 시간 포맷팅 (HH:MM:SS)
  String get formattedPlayTime {
    final hours = totalPlayTime.inHours;
    final minutes = totalPlayTime.inMinutes % 60;
    final seconds = totalPlayTime.inSeconds % 60;
    return '${hours.toString().padLeft(2, '0')}:'
        '${minutes.toString().padLeft(2, '0')}:'
        '${seconds.toString().padLeft(2, '0')}';
  }

  /// 클리어 날짜 포맷팅 (YYYY.MM.DD)
  String get formattedClearedDate {
    return '${clearedAt.year}.${clearedAt.month.toString().padLeft(2, '0')}.'
        '${clearedAt.day.toString().padLeft(2, '0')}';
  }

  /// copyWith 메서드 (아레나 장비 교환용)
  HallOfFameEntry copyWith({
    String? id,
    String? characterName,
    String? race,
    String? raceId,
    String? klass,
    int? level,
    int? totalPlayTimeMs,
    int? totalDeaths,
    int? monstersKilled,
    int? questsCompleted,
    DateTime? clearedAt,
    CombatStats? finalStats,
    List<EquipmentItem>? finalEquipment,
    List<Map<String, String>>? finalSkills,
  }) {
    return HallOfFameEntry(
      id: id ?? this.id,
      characterName: characterName ?? this.characterName,
      race: race ?? this.race,
      raceId: raceId ?? this.raceId,
      klass: klass ?? this.klass,
      level: level ?? this.level,
      totalPlayTimeMs: totalPlayTimeMs ?? this.totalPlayTimeMs,
      totalDeaths: totalDeaths ?? this.totalDeaths,
      monstersKilled: monstersKilled ?? this.monstersKilled,
      questsCompleted: questsCompleted ?? this.questsCompleted,
      clearedAt: clearedAt ?? this.clearedAt,
      finalStats: finalStats ?? this.finalStats,
      finalEquipment: finalEquipment ?? this.finalEquipment,
      finalSkills: finalSkills ?? this.finalSkills,
    );
  }

  /// GameState에서 HallOfFameEntry 생성
  factory HallOfFameEntry.fromGameState({
    required GameState state,
    required int totalDeaths,
    required int monstersKilled,
    CombatStats? combatStats,
  }) {
    return HallOfFameEntry(
      id: DateTime.now().millisecondsSinceEpoch.toString(),
      characterName: state.traits.name,
      race: state.traits.race,
      raceId: state.traits.raceId,
      klass: state.traits.klass,
      level: state.traits.level,
      totalPlayTimeMs: state.skillSystem.elapsedMs,
      totalDeaths: totalDeaths,
      monstersKilled: monstersKilled,
      questsCompleted: state.progress.questCount,
      clearedAt: DateTime.now(),
      finalStats: combatStats,
      finalEquipment: List<EquipmentItem>.from(state.equipment.items),
      finalSkills: state.skillBook.skills
          .map((s) => {'name': s.name, 'rank': s.rank})
          .toList(),
    );
  }

  /// JSON으로 직렬화
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'characterName': characterName,
      'race': race,
      'raceId': raceId,
      'klass': klass,
      'level': level,
      'totalPlayTimeMs': totalPlayTimeMs,
      'totalDeaths': totalDeaths,
      'monstersKilled': monstersKilled,
      'questsCompleted': questsCompleted,
      'clearedAt': clearedAt.toIso8601String(),
      'finalStats': finalStats?.toJson(),
      'finalEquipment': finalEquipment?.map((e) => e.toJson()).toList(),
      'finalSkills': finalSkills,
    };
  }

  /// JSON에서 역직렬화
  factory HallOfFameEntry.fromJson(Map<String, dynamic> json) {
    return HallOfFameEntry(
      id: json['id'] as String,
      characterName: json['characterName'] as String,
      race: json['race'] as String,
      raceId: json['raceId'] as String? ?? '',
      klass: json['klass'] as String,
      level: json['level'] as int,
      totalPlayTimeMs: json['totalPlayTimeMs'] as int,
      totalDeaths: json['totalDeaths'] as int? ?? 0,
      monstersKilled: json['monstersKilled'] as int? ?? 0,
      questsCompleted: json['questsCompleted'] as int? ?? 0,
      clearedAt: DateTime.parse(json['clearedAt'] as String),
      finalStats: json['finalStats'] != null
          ? CombatStats.fromJson(json['finalStats'] as Map<String, dynamic>)
          : null,
      finalEquipment: json['finalEquipment'] != null
          ? (json['finalEquipment'] as List<dynamic>)
                .map((e) => EquipmentItem.fromJson(e as Map<String, dynamic>))
                .toList()
          : null,
      finalSkills: json['finalSkills'] != null
          ? (json['finalSkills'] as List<dynamic>)
                .map((s) => Map<String, String>.from(s as Map))
                .toList()
          : null,
    );
  }
}

/// 명예의 전당 (Hall of Fame)
///
/// 클리어한 캐릭터 목록 관리
class HallOfFame {
  const HallOfFame({required this.entries});

  /// 명예의 전당 엔트리 목록 (클리어 시간 역순)
  final List<HallOfFameEntry> entries;

  /// 빈 명예의 전당
  factory HallOfFame.empty() => const HallOfFame(entries: []);

  /// 새 엔트리 추가
  HallOfFame addEntry(HallOfFameEntry entry) {
    final newEntries = List<HallOfFameEntry>.from(entries)
      ..add(entry)
      ..sort((a, b) => b.clearedAt.compareTo(a.clearedAt));
    return HallOfFame(entries: newEntries);
  }

  /// 엔트리 수
  int get count => entries.length;

  /// 비어있는지 확인
  bool get isEmpty => entries.isEmpty;

  /// ID로 엔트리 조회
  HallOfFameEntry? findById(String id) {
    for (final entry in entries) {
      if (entry.id == id) return entry;
    }
    return null;
  }

  /// 엔트리 업데이트 (아레나 장비 교환 후)
  HallOfFame updateEntry(HallOfFameEntry updated) {
    final newEntries = entries.map((e) {
      return e.id == updated.id ? updated : e;
    }).toList();
    return HallOfFame(entries: newEntries);
  }

  /// 엔트리 삭제 (디버그용)
  HallOfFame removeEntry(String id) {
    final newEntries = entries.where((e) => e.id != id).toList();
    return HallOfFame(entries: newEntries);
  }

  /// JSON으로 직렬화
  Map<String, dynamic> toJson() {
    return {'entries': entries.map((e) => e.toJson()).toList()};
  }

  /// JSON에서 역직렬화
  factory HallOfFame.fromJson(Map<String, dynamic> json) {
    final entriesJson = json['entries'] as List<dynamic>? ?? [];
    return HallOfFame(
      entries: entriesJson
          .map((e) => HallOfFameEntry.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

/// 아레나 순위 관련 extension
extension HallOfFameArenaX on HallOfFame {
  /// 아레나 점수 계산
  ///
  /// 점수 = (레벨 × 100) + 장비점수 + (전투력 / 10)
  static int calculateArenaScore(HallOfFameEntry entry) {
    // 1. 레벨 점수 (주요 지표)
    final levelScore = entry.level * 100;

    // 2. 장비 점수 (전체 슬롯 합계)
    final equipScore =
        entry.finalEquipment?.fold<int>(
          0,
          (sum, item) => sum + ItemService.calculateEquipmentScore(item),
        ) ??
        0;

    // 3. 전투력 점수 (ATK + DEF + HP/10)
    final combatScore = entry.finalStats != null
        ? (entry.finalStats!.atk +
              entry.finalStats!.def +
              entry.finalStats!.hpMax ~/ 10)
        : 0;

    return levelScore + equipScore + (combatScore ~/ 10);
  }

  /// 아레나 점수 기준 정렬된 엔트리 반환
  List<HallOfFameEntry> get rankedEntries {
    final sorted = List<HallOfFameEntry>.from(entries)
      ..sort((a, b) {
        final scoreA = calculateArenaScore(a);
        final scoreB = calculateArenaScore(b);
        if (scoreA != scoreB) return scoreB.compareTo(scoreA);
        // 동점일 경우 먼저 클리어한 캐릭터가 상위
        return a.clearedAt.compareTo(b.clearedAt);
      });
    return sorted;
  }

  /// 특정 캐릭터의 순위 반환 (1-based)
  int getRank(String characterId) {
    final ranked = rankedEntries;
    for (var i = 0; i < ranked.length; i++) {
      if (ranked[i].id == characterId) return i + 1;
    }
    return -1;
  }

  /// 상대의 베팅 슬롯 결정 (최저 장비 점수 슬롯)
  static EquipmentSlot findWeakestSlot(HallOfFameEntry entry) {
    final equipment = entry.finalEquipment ?? [];
    if (equipment.isEmpty) return EquipmentSlot.weapon;

    EquipmentItem weakest = equipment.first;
    int lowestScore = ItemService.calculateEquipmentScore(weakest);

    for (final item in equipment) {
      final score = ItemService.calculateEquipmentScore(item);
      if (score < lowestScore) {
        lowestScore = score;
        weakest = item;
      }
    }
    return weakest.slot;
  }
}
