import 'package:flutter/foundation.dart';

import 'package:asciineverdie/src/core/engine/ad_service.dart';
import 'package:asciineverdie/src/core/engine/chest_service.dart';
import 'package:asciineverdie/src/core/engine/iap_service.dart';
import 'package:asciineverdie/src/core/model/treasure_chest.dart';

/// 복귀 보상 서비스 (Phase 7)
///
/// 플레이어가 게임에 복귀했을 때 떠나있던 시간에 따라 보물 상자를 제공합니다.
/// - 최소 복귀 시간: 1시간
/// - 최대 복귀 시간: 24시간 (그 이상은 24시간으로 계산)
/// - 기본 보상: 4시간당 1상자
/// - 보너스 보상: 광고 시청 시 상자 2배
class ReturnRewardsService {
  ReturnRewardsService._() : _chestService = ChestService();

  static ReturnRewardsService? _instance;

  /// 싱글톤 인스턴스
  static ReturnRewardsService get instance {
    _instance ??= ReturnRewardsService._();
    return _instance!;
  }

  final ChestService _chestService;

  // ===========================================================================
  // 상수
  // ===========================================================================

  /// 최소 복귀 시간 (시간)
  static const int minHoursAway = 1;

  /// 최대 복귀 시간 (시간) - 이 이상은 동일 보상
  static const int maxHoursAway = 24;

  /// 상자 1개당 필요 시간 (시간)
  static const int hoursPerChest = 4;

  /// 최대 상자 개수 (무료 유저)
  static const int maxChestsFree = 5;

  /// 최대 상자 개수 (유료 유저)
  static const int maxChestsPaid = 10;

  // ===========================================================================
  // 보상 계산
  // ===========================================================================

  /// 복귀 보상 계산
  ///
  /// [lastPlayTime] 마지막 플레이 시각 (null이면 보상 없음)
  /// [currentTime] 현재 시각
  /// [isPaidUser] 유료 유저 여부 (최대 상자 개수 결정)
  /// Returns: 복귀 보상 데이터 (시간이 부족하면 hasReward = false)
  ReturnChestReward calculateReward({
    required DateTime? lastPlayTime,
    required DateTime currentTime,
    required bool isPaidUser,
  }) {
    // 마지막 플레이 시간이 없으면 보상 없음
    if (lastPlayTime == null) {
      debugPrint('[ReturnRewards] No lastPlayTime, no reward');
      return const ReturnChestReward(
        hoursAway: 0,
        chestCount: 0,
        bonusChestCount: 0,
      );
    }

    // 경과 시간 계산
    final difference = currentTime.difference(lastPlayTime);
    final hoursAway = difference.inHours;

    // 최소 시간 미만이면 보상 없음
    if (hoursAway < minHoursAway) {
      debugPrint('[ReturnRewards] Only $hoursAway hours, need $minHoursAway');
      return ReturnChestReward(
        hoursAway: hoursAway,
        chestCount: 0,
        bonusChestCount: 0,
      );
    }

    // 유료 유저: 오프라인 시간 2배 인정
    final creditedHours = isPaidUser ? hoursAway * 2 : hoursAway;

    // 최대 시간 초과 시 최대로 제한
    final effectiveHours = creditedHours > maxHoursAway
        ? maxHoursAway
        : creditedHours;

    // 상자 개수 계산
    final maxChests = isPaidUser ? maxChestsPaid : maxChestsFree;
    final rawChestCount = effectiveHours ~/ hoursPerChest;
    final chestCount = rawChestCount.clamp(0, maxChests);

    // 보너스 상자 (광고 시청 시 동일 개수 추가)
    final bonusChestCount = chestCount;

    debugPrint(
      '[ReturnRewards] $hoursAway hours away, '
      'chests=$chestCount, bonus=$bonusChestCount, paid=$isPaidUser',
    );

    return ReturnChestReward(
      hoursAway: hoursAway,
      chestCount: chestCount,
      bonusChestCount: bonusChestCount,
    );
  }

  // ===========================================================================
  // 상자 오픈
  // ===========================================================================

  /// 상자 오픈하여 보상 생성
  ///
  /// [count] 오픈할 상자 개수
  /// [playerLevel] 플레이어 레벨 (보상 스케일링용)
  List<ChestReward> openChests(int count, int playerLevel) {
    return _chestService.openMultipleChests(count, playerLevel);
  }

  // ===========================================================================
  // 보상 수령
  // ===========================================================================

  /// 기본 보상 수령 (광고 없이)
  ///
  /// [reward] 복귀 보상 데이터
  /// [playerLevel] 플레이어 레벨
  /// Returns: 오픈된 상자 보상 목록
  List<ChestReward> claimBasicReward(
    ReturnChestReward reward,
    int playerLevel,
  ) {
    if (!reward.hasReward) return [];
    debugPrint(
      '[ReturnRewards] Basic reward claimed: ${reward.chestCount} chests',
    );
    return openChests(reward.chestCount, playerLevel);
  }

  /// 보너스 보상 수령 (광고 시청 후)
  ///
  /// 유료 유저: 무료 보너스
  /// 무료 유저: 리워드 광고 시청 후 보너스
  /// [reward] 복귀 보상 데이터
  /// [playerLevel] 플레이어 레벨
  /// Returns: 오픈된 보너스 상자 보상 목록 (광고 실패 시 빈 목록)
  Future<List<ChestReward>> claimBonusReward(
    ReturnChestReward reward,
    int playerLevel,
  ) async {
    if (!reward.hasReward || reward.bonusChestCount <= 0) return [];

    // 유료 유저는 무료 보너스
    if (IAPService.instance.isAdRemovalPurchased) {
      debugPrint(
        '[ReturnRewards] Bonus claimed (paid user): '
        '${reward.bonusChestCount} chests',
      );
      return openChests(reward.bonusChestCount, playerLevel);
    }

    // 무료 유저는 리워드 광고 필요
    List<ChestReward> bonusRewards = [];
    final adResult = await AdService.instance.showRewardedAd(
      adType: AdType.rewardReturn, // 복귀 보상용 리워드 광고
      onRewarded: () {
        bonusRewards = openChests(reward.bonusChestCount, playerLevel);
      },
    );

    if (adResult == AdResult.completed || adResult == AdResult.debugSkipped) {
      debugPrint(
        '[ReturnRewards] Bonus claimed (free user with ad): '
        '${bonusRewards.length} chests',
      );
      return bonusRewards;
    }

    debugPrint('[ReturnRewards] Bonus claim failed: $adResult');
    return [];
  }

  // ===========================================================================
  // 시간 포맷팅
  // ===========================================================================

  /// 복귀 시간을 표시용 문자열로 변환
  String formatHoursAway(int hours) {
    if (hours < 24) {
      return '${hours}h';
    }
    final days = hours ~/ 24;
    final remainingHours = hours % 24;
    if (remainingHours == 0) {
      return '${days}d';
    }
    return '${days}d ${remainingHours}h';
  }
}
