import 'package:freezed_annotation/freezed_annotation.dart';

import 'package:asciineverdie/src/core/model/game_state.dart';

part 'monetization_state.freezed.dart';
part 'monetization_state.g.dart';

/// 수익화 시스템 상태
///
/// IAP 구매 여부, 광고 관련 버프, 복귀 보상 등을 관리
@freezed
class MonetizationState with _$MonetizationState {
  const MonetizationState._();

  const factory MonetizationState({
    /// IAP 광고 제거 구매 여부
    @Default(false) bool adRemovalPurchased,

    /// 캐릭터 생성 굴리기 남은 횟수 (0-5)
    @Default(5) int rollsRemaining,

    /// 되돌리기 남은 횟수
    @Default(1) int undoRemaining,

    /// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
    // ignore: invalid_annotation_target
    @JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
    List<Stats>? rollHistory,

    /// 자동부활 버프 종료 시점 (elapsedMs 기준)
    int? autoReviveEndMs,

    /// 5배속 버프 종료 시점 (elapsedMs 기준)
    int? speedBoostEndMs,

    /// 마지막 플레이 시각 (복귀 보상 계산용)
    // ignore: invalid_annotation_target
    @JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
    DateTime? lastPlayTime,

    /// 미개봉 보물 상자 개수
    @Default(0) int pendingChests,

    /// 행운의 부적 버프 종료 시점 (elapsedMs 기준)
    int? luckyCharmEndMs,
  }) = _MonetizationState;

  factory MonetizationState.fromJson(Map<String, dynamic> json) =>
      _$MonetizationStateFromJson(json);

  /// 기본 상태 생성 (신규 게임)
  factory MonetizationState.initial({bool isPaidUser = false}) {
    return MonetizationState(
      adRemovalPurchased: isPaidUser,
      rollsRemaining: 5,
      undoRemaining: isPaidUser ? 3 : 1,
      rollHistory: null,
      pendingChests: 0,
    );
  }

  // ===========================================================================
  // 유틸리티 메서드
  // ===========================================================================

  /// 유료 사용자 여부
  bool get isPaidUser => adRemovalPurchased;

  /// 무료 사용자 여부
  bool get isFreeUser => !adRemovalPurchased;

  /// 자동부활 버프 활성 여부 (elapsedMs 기준)
  bool isAutoReviveActive(int elapsedMs) {
    if (autoReviveEndMs == null) return false;
    return elapsedMs < autoReviveEndMs!;
  }

  /// 5배속 버프 활성 여부 (elapsedMs 기준)
  /// 유료 사용자는 항상 활성
  bool isSpeedBoostActive(int elapsedMs) {
    if (isPaidUser) return true;
    if (speedBoostEndMs == null) return false;
    return elapsedMs < speedBoostEndMs!;
  }

  /// 행운의 부적 버프 활성 여부 (elapsedMs 기준)
  bool isLuckyCharmActive(int elapsedMs) {
    if (luckyCharmEndMs == null) return false;
    return elapsedMs < luckyCharmEndMs!;
  }

  /// 굴리기 가능 여부
  bool get canRoll => rollsRemaining > 0;

  /// 되돌리기 가능 여부
  bool canUndo(int historyLength) {
    if (undoRemaining <= 0) return false;
    if (rollHistory == null || rollHistory!.isEmpty) return false;
    return historyLength > 0;
  }

  /// 실제 사용 가능한 되돌리기 횟수
  int availableUndos(int historyLength) {
    if (rollHistory == null) return 0;
    final historyAvailable = rollHistory!.length;
    return undoRemaining < historyAvailable ? undoRemaining : historyAvailable;
  }

  /// 최대 보물 상자 개수
  int get maxChests => isPaidUser ? 10 : 5;

  /// 보물 상자가 가득 찼는지 여부
  bool get isChestsFull => pendingChests >= maxChests;
}

// =============================================================================
// JSON 변환 헬퍼
// =============================================================================

/// Stats 리스트 → JSON
List<Map<String, dynamic>>? _statsListToJson(List<Stats>? stats) {
  if (stats == null) return null;
  return stats
      .map(
        (s) => {
          'str': s.str,
          'con': s.con,
          'dex': s.dex,
          'int': s.intelligence,
          'wis': s.wis,
          'cha': s.cha,
          'hpMax': s.hpMax,
          'mpMax': s.mpMax,
        },
      )
      .toList();
}

/// JSON → Stats 리스트
List<Stats>? _statsListFromJson(List<dynamic>? json) {
  if (json == null) return null;
  return json.map((e) {
    final m = e as Map<String, dynamic>;
    return Stats(
      str: m['str'] as int? ?? 0,
      con: m['con'] as int? ?? 0,
      dex: m['dex'] as int? ?? 0,
      intelligence: m['int'] as int? ?? 0,
      wis: m['wis'] as int? ?? 0,
      cha: m['cha'] as int? ?? 0,
      hpMax: m['hpMax'] as int? ?? 0,
      mpMax: m['mpMax'] as int? ?? 0,
    );
  }).toList();
}

/// DateTime → JSON (밀리초 타임스탬프)
int? _dateTimeToJson(DateTime? dateTime) {
  return dateTime?.millisecondsSinceEpoch;
}

/// JSON → DateTime
DateTime? _dateTimeFromJson(int? timestamp) {
  if (timestamp == null) return null;
  return DateTime.fromMillisecondsSinceEpoch(timestamp);
}
