import 'dart:async';

import 'package:askiineverdie/src/core/engine/progress_loop.dart';
import 'package:askiineverdie/src/core/engine/progress_service.dart';
import 'package:askiineverdie/src/core/engine/resurrection_service.dart';
import 'package:askiineverdie/src/core/engine/shop_service.dart';
import 'package:askiineverdie/src/core/model/game_state.dart';
import 'package:askiineverdie/src/core/model/game_statistics.dart';
import 'package:askiineverdie/src/core/storage/save_manager.dart';
import 'package:askiineverdie/src/core/storage/statistics_storage.dart';
import 'package:flutter/foundation.dart';

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

/// Presentation-friendly wrapper that owns ProgressLoop and SaveManager.
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,
  }) : _tickInterval = tickInterval,
       _now = now ?? DateTime.now,
       _statisticsStorage = statisticsStorage ?? StatisticsStorage();

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

  final Duration _tickInterval;
  final DateTime Function() _now;

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

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

  // 통계 관련 필드
  SessionStatistics _sessionStats = SessionStatistics.empty();
  CumulativeStatistics _cumulativeStats = CumulativeStatistics.empty();
  int _previousLevel = 0;
  int _previousGold = 0;
  int _previousMonstersKilled = 0;
  int _previousQuestsCompleted = 0;

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

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

  /// 누적 통계
  CumulativeStatistics get cumulativeStats => _cumulativeStats;

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

  Future<void> startNew(
    GameState initialState, {
    bool cheatsEnabled = false,
    bool isNewGame = true,
  }) async {
    await _stopLoop(saveOnStop: false);

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

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

    // 통계 초기화
    if (isNewGame) {
      _sessionStats = SessionStatistics.empty();
      await _statisticsStorage.recordGameStart();
    }
    _initPreviousValues(state);

    _loop = ProgressLoop(
      initialState: state,
      progressService: progressService,
      saveManager: saveManager,
      autoSaveConfig: autoSaveConfig,
      tickInterval: _tickInterval,
      now: _now,
      cheatsEnabled: cheatsEnabled,
      onPlayerDied: _onPlayerDied,
    );

    _subscription = _loop!.stream.listen((next) {
      _updateStatistics(next);
      _state = next;
      notifyListeners();
    });

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

  /// 이전 값 초기화 (통계 변화 추적용)
  void _initPreviousValues(GameState state) {
    _previousLevel = state.traits.level;
    _previousGold = state.inventory.gold;
    _previousMonstersKilled = state.progress.monstersKilled;
    _previousQuestsCompleted = state.progress.questCount;
  }

  /// 상태 변화에 따른 통계 업데이트
  void _updateStatistics(GameState next) {
    // 플레이 시간 업데이트
    _sessionStats = _sessionStats.updatePlayTime(next.skillSystem.elapsedMs);

    // 레벨업 감지
    if (next.traits.level > _previousLevel) {
      final levelUps = next.traits.level - _previousLevel;
      for (var i = 0; i < levelUps; i++) {
        _sessionStats = _sessionStats.recordLevelUp();
      }
      _previousLevel = next.traits.level;

      // 최고 레벨 업데이트
      unawaited(_statisticsStorage.updateHighestLevel(next.traits.level));
    }

    // 골드 변화 감지
    if (next.inventory.gold > _previousGold) {
      final earned = next.inventory.gold - _previousGold;
      _sessionStats = _sessionStats.recordGoldEarned(earned);

      // 최대 골드 업데이트
      unawaited(_statisticsStorage.updateHighestGold(next.inventory.gold));
    } else if (next.inventory.gold < _previousGold) {
      final spent = _previousGold - next.inventory.gold;
      _sessionStats = _sessionStats.recordGoldSpent(spent);
    }
    _previousGold = next.inventory.gold;

    // 몬스터 처치 감지
    if (next.progress.monstersKilled > _previousMonstersKilled) {
      final kills = next.progress.monstersKilled - _previousMonstersKilled;
      for (var i = 0; i < kills; i++) {
        _sessionStats = _sessionStats.recordKill();
      }
      _previousMonstersKilled = next.progress.monstersKilled;
    }

    // 퀘스트 완료 감지
    if (next.progress.questCount > _previousQuestsCompleted) {
      final quests = next.progress.questCount - _previousQuestsCompleted;
      for (var i = 0; i < quests; i++) {
        _sessionStats = _sessionStats.recordQuestComplete();
      }
      _previousQuestsCompleted = next.progress.questCount;
    }
  }

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

  /// 세션 통계를 누적 통계에 병합
  Future<void> mergeSessionStats() async {
    await _statisticsStorage.mergeSession(_sessionStats);
    _cumulativeStats = await _statisticsStorage.loadCumulative();
    notifyListeners();
  }

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

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

    await startNew(loaded, cheatsEnabled: cheatsEnabled, 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;
    _loop = null;
    _subscription = null;

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

  // ============================================================================
  // Phase 4: 사망/부활 처리
  // ============================================================================

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

  /// 플레이어 부활 처리 (상태만 업데이트, 게임 재개는 별도로)
  ///
  /// HP/MP 회복, 빈 슬롯에 장비 자동 구매
  /// 게임 재개는 resumeAfterResurrection()으로 별도 호출 필요
  Future<void> resurrect() async {
    if (_state == null || !_state!.isDead) return;

    // ResurrectionService를 사용하여 부활 처리
    final shopService = ShopService(rng: _state!.rng);
    final resurrectionService = ResurrectionService(shopService: shopService);

    final resurrectedState = resurrectionService.processResurrection(_state!);

    // 상태 업데이트 (게임 재개 없이)
    _state = resurrectedState;
    _status = GameSessionStatus.idle; // 사망 상태 해제

    // 저장
    await saveManager.saveState(resurrectedState);

    notifyListeners();
  }

  /// 부활 후 게임 재개
  ///
  /// resurrect() 호출 후 애니메이션이 끝난 뒤 호출
  Future<void> resumeAfterResurrection() async {
    if (_state == null) return;

    // 게임 재개
    await startNew(_state!, cheatsEnabled: _cheatsEnabled, isNewGame: false);
  }

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