import 'dart:async';

import 'package:asciineverdie/src/core/engine/iap_service.dart';
import 'package:asciineverdie/src/core/engine/progress_loop.dart';
import 'package:asciineverdie/src/core/engine/progress_service.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/monetization_state.dart';
import 'package:asciineverdie/src/core/model/treasure_chest.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/statistics_storage.dart';
import 'package:asciineverdie/src/features/game/managers/game_statistics_manager.dart';
import 'package:asciineverdie/src/features/game/managers/hall_of_fame_manager.dart';
import 'package:asciineverdie/src/features/game/managers/resurrection_manager.dart';
import 'package:asciineverdie/src/features/game/managers/return_rewards_manager.dart';
import 'package:asciineverdie/src/features/game/managers/speed_boost_manager.dart';
import 'package:flutter/foundation.dart';

enum GameSessionStatus { idle, loading, running, error, dead, complete }

/// Presentation-friendly wrapper that owns ProgressLoop and SaveManager.
///
/// 게임 루프 관리를 담당하며, 대부분의 기능은 매니저에 위임합니다.
/// - 통계: GameStatisticsManager
/// - 속도 부스트: SpeedBoostManager
/// - 복귀 보상: ReturnRewardsManager
/// - 부활: ResurrectionManager
/// - 명예의 전당: HallOfFameManager
class GameSessionController extends ChangeNotifier {
  GameSessionController({
    required this.progressService,
    required this.saveManager,
    this.autoSaveConfig = const AutoSaveConfig(),
    Duration tickInterval = const Duration(milliseconds: 50),
    DateTime Function()? now,
    StatisticsStorage? statisticsStorage,
    HallOfFameStorage? hallOfFameStorage,
  }) : _tickInterval = tickInterval,
       _now = now ?? DateTime.now {
    // 매니저 초기화
    _statisticsManager = GameStatisticsManager(
      statisticsStorage: statisticsStorage,
    );
    _hallOfFameManager = HallOfFameManager(
      hallOfFameStorage: hallOfFameStorage,
    );
    _speedBoostManager = SpeedBoostManager(
      cheatsEnabledGetter: () => _cheatsEnabled,
      getAvailableSpeeds: _hallOfFameManager.getAvailableSpeeds,
    );
    _returnRewardsManager = ReturnRewardsManager();
    _resurrectionManager = ResurrectionManager();

    // 매니저 콜백 설정
    _speedBoostManager.onStateChanged = notifyListeners;
    _returnRewardsManager.onReturnRewardAvailable = (reward) {
      onReturnRewardAvailable?.call(reward);
    };
  }

  final ProgressService progressService;
  final SaveManager saveManager;
  final AutoSaveConfig autoSaveConfig;

  final Duration _tickInterval;
  final DateTime Function() _now;

  // 매니저들
  late final GameStatisticsManager _statisticsManager;
  late final HallOfFameManager _hallOfFameManager;
  late final SpeedBoostManager _speedBoostManager;
  late final ReturnRewardsManager _returnRewardsManager;
  late final ResurrectionManager _resurrectionManager;

  ProgressLoop? _loop;
  StreamSubscription<GameState>? _subscription;
  bool _cheatsEnabled = false;

  GameSessionStatus _status = GameSessionStatus.idle;
  GameState? _state;
  String? _error;

  // 복귀 보상 상태 (Phase 7)
  MonetizationState _monetization = MonetizationState.initial();

  /// 복귀 보상 콜백 (UI에서 다이얼로그 표시용)
  void Function(ReturnChestReward reward)? onReturnRewardAvailable;

  // ==========================================================================
  // Getters
  // ==========================================================================

  GameSessionStatus get status => _status;
  GameState? get state => _state;
  String? get error => _error;
  bool get isRunning => _status == GameSessionStatus.running;
  bool get cheatsEnabled => kDebugMode && _cheatsEnabled;

  /// 자동 부활 활성화 여부
  bool get autoResurrect => _resurrectionManager.autoResurrect;

  /// 자동 부활 설정
  void setAutoResurrect(bool value) {
    _resurrectionManager.autoResurrect = value;
    notifyListeners();
  }

  /// 현재 세션 통계
  SessionStatistics get sessionStats => _statisticsManager.sessionStats;

  /// 누적 통계
  CumulativeStatistics get cumulativeStats =>
      _statisticsManager.cumulativeStats;

  /// 현재 ProgressLoop 인스턴스 (치트 기능용)
  ProgressLoop? get loop => _loop;

  /// 광고 배속 배율 (릴리즈: 5x, 디버그빌드+디버그모드: 20x)
  int get adSpeedMultiplier => _speedBoostManager.speedBoostMultiplier;

  /// 2x 배속 해금 여부 (명예의 전당에 캐릭터가 있으면 true)
  bool get has2xUnlocked => _loop?.availableSpeeds.contains(2) ?? false;

  /// 사망 상태 여부
  bool get isDead =>
      _status == GameSessionStatus.dead || (_state?.isDead ?? false);

  /// 게임 클리어 여부
  bool get isComplete => _status == GameSessionStatus.complete;

  // 속도 부스트 관련 getters (매니저 위임)
  bool get isSpeedBoostActive => _speedBoostManager.isSpeedBoostActive;
  bool get isShowingAd => _speedBoostManager.isShowingAd;
  bool get isRecentlyShowedAd => _speedBoostManager.isRecentlyShowedAd;
  int get speedBoostMultiplier => _speedBoostManager.speedBoostMultiplier;
  int get speedBoostDuration => _speedBoostManager.speedBoostDuration;

  int get speedBoostRemainingSeconds => _speedBoostManager.getRemainingSeconds(
    _monetization,
    _state?.skillSystem.elapsedMs ?? 0,
  );

  int get currentSpeedMultiplier =>
      _speedBoostManager.getCurrentSpeedMultiplier(_loop);

  // 복귀 보상 관련 getters (매니저 위임)
  MonetizationState get monetization => _monetization;
  ReturnChestReward? get pendingReturnReward =>
      _returnRewardsManager.pendingReturnReward;

  // ==========================================================================
  // 게임 루프 관리
  // ==========================================================================

  Future<void> startNew(
    GameState initialState, {
    bool cheatsEnabled = false,
    bool isNewGame = true,
  }) async {
    // 기존 배속 보존 (부활/재개 시 유지)
    final previousSpeed =
        _loop?.speedMultiplier ?? _speedBoostManager.savedSpeedMultiplier;

    await _stopLoop(saveOnStop: false);

    // 새 게임인 경우 초기화 (프롤로그 태스크 설정)
    final state = isNewGame
        ? progressService.initializeNewGame(initialState)
        : initialState;

    _state = state;
    _error = null;
    _status = GameSessionStatus.running;
    _cheatsEnabled = cheatsEnabled;

    // IAP 구매 상태를 MonetizationState에 동기화
    // (테스트 환경에서는 InAppPurchase 플랫폼 채널 미등록으로 예외 발생 가능)
    try {
      final isPaid = IAPService.instance.isAdRemovalPurchased;
      if (_monetization.adRemovalPurchased != isPaid) {
        _monetization = _monetization.copyWith(adRemovalPurchased: isPaid);
      }
    } catch (_) {
      // 비모바일 플랫폼 또는 테스트 환경에서는 무시
    }

    // 통계 초기화
    if (isNewGame) {
      await _statisticsManager.initializeForNewGame();
    } else {
      _statisticsManager.restoreFromLoadedGame(state);
    }
    _statisticsManager.initPreviousValues(state);

    // 명예의 전당 체크 → 기본 가용 배속 결정
    final baseAvailableSpeeds = await _hallOfFameManager.getAvailableSpeeds();
    final hasHallOfFame = baseAvailableSpeeds.contains(2);

    // 기본 배속 결정 (부스트 미적용 시)
    final int baseSpeed;
    if (isNewGame) {
      baseSpeed = hasHallOfFame ? 2 : 1;
    } else {
      baseSpeed = (hasHallOfFame && previousSpeed < 2) ? 2 : previousSpeed;
    }

    // 배속 부스트 활성화 상태면 부스트 배속 적용, 아니면 기본 배속
    final speedConfig = _speedBoostManager.calculateInitialSpeeds(
      baseAvailableSpeeds: baseAvailableSpeeds,
      baseSpeed: baseSpeed,
    );

    _loop = ProgressLoop(
      initialState: state,
      progressService: progressService,
      saveManager: saveManager,
      autoSaveConfig: autoSaveConfig,
      tickInterval: _tickInterval,
      now: _now,
      cheatsEnabled: cheatsEnabled,
      onPlayerDied: _onPlayerDied,
      onGameComplete: _onGameComplete,
      availableSpeeds: speedConfig.speeds,
      initialSpeedMultiplier: speedConfig.initialSpeed,
    );

    _subscription = _loop!.stream.listen((next) {
      final elapsedMs = next.skillSystem.elapsedMs;
      // 버프 만료 체크 (게임 시간 기준)
      _checkBuffExpiries(elapsedMs);
      _statisticsManager.updateStatistics(next);
      _state = next;
      notifyListeners();
    });

    _loop!.start();
    notifyListeners();
  }

  /// 매 틱마다 버프 만료 체크
  void _checkBuffExpiries(int elapsedMs) {
    // 속도 부스트 만료 체크
    final boostEnded = _speedBoostManager.checkExpiry(
      elapsedMs: elapsedMs,
      monetization: _monetization,
      loop: _loop,
    );
    if (boostEnded) {
      _monetization = _monetization.copyWith(speedBoostEndMs: null);
    }

    // 자동부활 버프 만료 체크
    final endMs = _monetization.autoReviveEndMs;
    if (endMs != null && elapsedMs >= endMs) {
      _monetization = _monetization.copyWith(autoReviveEndMs: null);
      debugPrint('[GameSession] Auto-revive buff expired');
      notifyListeners();
    }
  }

  /// 누적 통계 로드
  Future<void> loadCumulativeStats() async {
    await _statisticsManager.loadCumulativeStats();
    notifyListeners();
  }

  /// 세션 통계를 누적 통계에 병합
  Future<void> mergeSessionStats() async {
    await _statisticsManager.mergeSessionStats();
    notifyListeners();
  }

  Future<void> loadAndStart({String? fileName}) async {
    _status = GameSessionStatus.loading;
    _error = null;
    notifyListeners();

    final (outcome, loaded, savedCheatsEnabled, savedMonetization) =
        await saveManager.loadState(fileName: fileName);
    if (!outcome.success || loaded == null) {
      _status = GameSessionStatus.error;
      _error = outcome.error ?? 'Unknown error';
      notifyListeners();
      return;
    }

    // 저장된 수익화(monetization) 상태 복원, IAP 구매 상태 동기화
    _monetization = savedMonetization ?? MonetizationState.initial();
    try {
      final isPaid = IAPService.instance.isAdRemovalPurchased;
      if (_monetization.adRemovalPurchased != isPaid) {
        _monetization = _monetization.copyWith(adRemovalPurchased: isPaid);
      }
    } catch (_) {
      // 비모바일 플랫폼 또는 테스트 환경에서는 무시
    }

    // 복귀 보상 체크 (Phase 7)
    _returnRewardsManager.checkReturnRewards(
      monetization: _monetization,
      loaded: loaded,
    );

    // 저장된 치트 모드 상태 복원
    await startNew(loaded, cheatsEnabled: savedCheatsEnabled, isNewGame: false);
  }

  Future<void> pause({bool saveOnStop = false}) async {
    await _stopLoop(saveOnStop: saveOnStop);
    _status = GameSessionStatus.idle;
    notifyListeners();
  }

  /// 일시 정지 상태에서 재개
  Future<void> resume() async {
    if (_state == null || _status != GameSessionStatus.idle) return;
    await startNew(_state!, cheatsEnabled: _cheatsEnabled, isNewGame: false);
  }

  /// 일시 정지/재개 토글
  Future<void> togglePause() async {
    if (isRunning) {
      await pause(saveOnStop: true);
    } else if (_state != null && _status == GameSessionStatus.idle) {
      await resume();
    }
  }

  @override
  void dispose() {
    final stop = _stopLoop(saveOnStop: false);
    if (stop != null) {
      unawaited(stop);
    }
    super.dispose();
  }

  Future<void>? _stopLoop({required bool saveOnStop}) {
    final loop = _loop;
    final sub = _subscription;

    // 배속 저장 (resume 시 복원용)
    if (loop != null) {
      _speedBoostManager.savedSpeedMultiplier = loop.speedMultiplier;
    }

    _loop = null;
    _subscription = null;

    sub?.cancel();
    if (loop == null) return null;
    return loop.stop(saveOnStop: saveOnStop);
  }

  // ==========================================================================
  // 사망/부활 처리
  // ==========================================================================

  /// 플레이어 사망 콜백 (ProgressLoop에서 호출)
  void _onPlayerDied() {
    _statisticsManager.recordDeath();
    _status = GameSessionStatus.dead;
    notifyListeners();

    // 자동 부활 조건 확인
    final elapsedMs = _state?.skillSystem.elapsedMs ?? 0;
    final shouldAutoResurrect = _resurrectionManager.shouldAutoResurrect(
      monetization: _monetization,
      elapsedMs: elapsedMs,
    );

    if (shouldAutoResurrect) {
      _scheduleAutoResurrect();
    }
  }

  /// 자동 부활 예약 (Auto-Resurrection Scheduler)
  void _scheduleAutoResurrect() {
    Future.delayed(const Duration(milliseconds: 800), () async {
      if (_status != GameSessionStatus.dead) return;

      // 자동 부활 조건 재확인
      final elapsedMs = _state?.skillSystem.elapsedMs ?? 0;
      final shouldAutoResurrect = _resurrectionManager.shouldAutoResurrect(
        monetization: _monetization,
        elapsedMs: elapsedMs,
      );

      if (shouldAutoResurrect) {
        await resurrect();
        await resumeAfterResurrection();
      }
    });
  }

  /// 플레이어 부활 처리 (상태만 업데이트, 게임 재개는 별도로)
  Future<void> resurrect() async {
    if (_state == null || !_state!.isDead) return;

    final resurrectedState = await _resurrectionManager.processResurrection(
      state: _state!,
      saveManager: saveManager,
      cheatsEnabled: _cheatsEnabled,
      monetization: _monetization,
    );

    if (resurrectedState != null) {
      _state = resurrectedState;
      _status = GameSessionStatus.idle;
      notifyListeners();
    }
  }

  /// 부활 후 게임 재개
  Future<void> resumeAfterResurrection() async {
    if (_state == null) return;
    await startNew(_state!, cheatsEnabled: _cheatsEnabled, isNewGame: false);
  }

  /// 광고 부활 (HP 100% + 아이템 복구 + 10분 자동부활 버프)
  Future<void> adRevive() async {
    if (_state == null || !_state!.isDead) return;

    final result = await _resurrectionManager.processAdRevive(
      state: _state!,
      saveManager: saveManager,
      cheatsEnabled: _cheatsEnabled,
      monetization: _monetization,
    );

    if (result.success) {
      _state = result.state;
      _monetization = result.monetization;
      _status = GameSessionStatus.idle;
      notifyListeners();
    }
  }

  // ==========================================================================
  // 명예의 전당
  // ==========================================================================

  /// 게임 클리어 콜백 (ProgressLoop에서 호출, Act V 완료 시)
  void _onGameComplete() {
    _status = GameSessionStatus.complete;
    notifyListeners();

    unawaited(_registerToHallOfFame());
  }

  /// 명예의 전당 등록
  Future<void> _registerToHallOfFame() async {
    if (_state == null) {
      debugPrint('[HallOfFame] _state is null, skipping registration');
      return;
    }

    await _hallOfFameManager.registerCharacter(
      state: _state!,
      saveManager: saveManager,
      statisticsManager: _statisticsManager,
    );
  }

  /// 테스트 캐릭터 생성 (디버그 모드 전용)
  Future<bool> createTestCharacter() async {
    if (_state == null) {
      debugPrint('[TestCharacter] _state is null');
      return false;
    }

    await _stopLoop(saveOnStop: false);

    final success = await _hallOfFameManager.createTestCharacter(
      state: _state!,
      saveManager: saveManager,
    );

    if (success) {
      _state = null;
      _status = GameSessionStatus.idle;
      notifyListeners();
    }

    return success;
  }

  // ==========================================================================
  // 속도 부스트 (Phase 6)
  // ==========================================================================

  /// 속도 부스트 활성화 (광고 시청 후)
  Future<bool> activateSpeedBoost() async {
    final (success, updatedMonetization) = await _speedBoostManager
        .activateSpeedBoost(
          loop: _loop,
          monetization: _monetization,
          currentElapsedMs: _state?.skillSystem.elapsedMs ?? 0,
        );

    if (success) {
      _monetization = updatedMonetization;
      notifyListeners();
    }

    return success;
  }

  /// 속도 부스트 수동 취소
  void cancelSpeedBoost() {
    _monetization = _speedBoostManager.cancelSpeedBoost(
      loop: _loop,
      monetization: _monetization,
    );
    notifyListeners();
  }

  // ==========================================================================
  // 복귀 보상 (Phase 7)
  // ==========================================================================

  /// 복귀 보상 수령 완료 (상자 보상 적용)
  Future<void> applyReturnReward(List<ChestReward> rewards) async {
    if (_state == null) return;

    final updatedState = await _returnRewardsManager.applyReturnReward(
      rewards: rewards,
      state: _state!,
      loop: _loop,
      saveManager: saveManager,
      cheatsEnabled: _cheatsEnabled,
      monetization: _monetization,
    );

    if (updatedState != null) {
      _state = updatedState;
      notifyListeners();
    }
  }

  /// 복귀 보상 건너뛰기
  void skipReturnReward() {
    _returnRewardsManager.skipReturnReward();
  }
}
