import 'dart:async';

import 'package:asciineverdie/src/core/model/game_state.dart';
import 'package:asciineverdie/src/core/storage/save_manager.dart';
import 'package:asciineverdie/src/core/engine/progress_service.dart';

class AutoSaveConfig {
  const AutoSaveConfig({
    this.onLevelUp = true,
    this.onQuestComplete = true,
    this.onActComplete = true,
    this.onStop = true,
    this.onDeath = true,
  });

  final bool onLevelUp;
  final bool onQuestComplete;
  final bool onActComplete;
  final bool onStop;

  /// 사망 시 자동 저장 (Phase 4)
  final bool onDeath;

  bool shouldSave(ProgressTickResult result) {
    return (onLevelUp && result.leveledUp) ||
        (onQuestComplete && result.completedQuest) ||
        (onActComplete && result.completedAct) ||
        (onDeath && result.playerDied);
  }
}

/// Runs the periodic timer loop that advances tasks/quests/plots.
class ProgressLoop {
  ProgressLoop({
    required GameState initialState,
    required this.progressService,
    this.saveManager,
    Duration tickInterval = const Duration(milliseconds: 50),
    AutoSaveConfig autoSaveConfig = const AutoSaveConfig(),
    DateTime Function()? now,
    this.cheatsEnabled = false,
    this.onPlayerDied,
    this.onGameComplete,
    List<int> availableSpeeds = const [1, 5],
    int initialSpeedMultiplier = 1,
  }) : _state = initialState,
       _tickInterval = tickInterval,
       _autoSaveConfig = autoSaveConfig,
       _now = now ?? DateTime.now,
       _stateController = StreamController<GameState>.broadcast(),
       _availableSpeeds = availableSpeeds.isNotEmpty ? availableSpeeds : [1],
       _speedMultiplier = initialSpeedMultiplier;

  final ProgressService progressService;
  final SaveManager? saveManager;
  final Duration _tickInterval;

  /// 플레이어 사망 시 콜백 (Phase 4)
  final void Function()? onPlayerDied;

  /// 게임 클리어 시 콜백 (Act V 완료)
  final void Function()? onGameComplete;
  final AutoSaveConfig _autoSaveConfig;
  final DateTime Function() _now;
  final StreamController<GameState> _stateController;
  bool cheatsEnabled;

  Timer? _timer;
  int? _lastTickMs;
  int _speedMultiplier;
  List<int> _availableSpeeds;

  GameState get current => _state;
  Stream<GameState> get stream => _stateController.stream;
  GameState _state;

  /// 가용 배속 목록
  List<int> get availableSpeeds => List.unmodifiable(_availableSpeeds);

  /// 현재 배속 (1x, 2x, 5x)
  int get speedMultiplier => _speedMultiplier;

  /// 배속 순환: 가용 배속 목록 순환
  /// 명예의 전당에 캐릭터 없으면: 1 -> 5 -> 1
  /// 명예의 전당에 캐릭터 있으면: 1 -> 2 -> 5 -> 1
  void cycleSpeed() {
    final currentIndex = _availableSpeeds.indexOf(_speedMultiplier);
    final nextIndex = (currentIndex + 1) % _availableSpeeds.length;
    _speedMultiplier = _availableSpeeds[nextIndex];
  }

  /// 특정 배속으로 직접 설정
  /// 가용 배속 목록에 있는 경우에만 설정
  void setSpeed(int speed) {
    if (_availableSpeeds.contains(speed)) {
      _speedMultiplier = speed;
    }
  }

  /// 가용 배속 목록 업데이트 (명예의 전당 상태 변경 시)
  void updateAvailableSpeeds(List<int> speeds) {
    if (speeds.isEmpty) return;
    _availableSpeeds = speeds;
    // 현재 배속이 새 목록에 없으면 첫 번째로 리셋
    if (!_availableSpeeds.contains(_speedMultiplier)) {
      _speedMultiplier = _availableSpeeds.first;
    }
  }

  void start() {
    _lastTickMs = _now().millisecondsSinceEpoch;
    _timer ??= Timer.periodic(_tickInterval, (_) => tickOnce());
  }

  Future<void> stop({bool saveOnStop = false}) async {
    _timer?.cancel();
    _timer = null;
    if (saveOnStop && _autoSaveConfig.onStop && saveManager != null) {
      await saveManager!.saveState(_state, cheatsEnabled: cheatsEnabled);
    }
  }

  void dispose() {
    _timer?.cancel();
    _stateController.close();
  }

  /// Run one iteration of the loop (used by Timer or manual stepping).
  GameState tickOnce({int? deltaMillis}) {
    // 사망 상태면 틱 진행 안 함 (Phase 4)
    if (_state.isDead) {
      return _state;
    }

    final baseDelta = deltaMillis ?? _computeDelta();
    final delta = baseDelta * _speedMultiplier;
    final result = progressService.tick(_state, delta);
    _state = result.state;
    _stateController.add(_state);

    if (saveManager != null && _autoSaveConfig.shouldSave(result)) {
      saveManager!.saveState(_state, cheatsEnabled: cheatsEnabled);
    }

    // 사망 시 루프 정지 및 콜백 호출 (Phase 4)
    if (result.playerDied) {
      _timer?.cancel();
      _timer = null;
      onPlayerDied?.call();
    }

    // 게임 클리어 시 루프 정지 및 콜백 호출 (Act V 완료)
    if (result.gameComplete) {
      _timer?.cancel();
      _timer = null;
      onGameComplete?.call();
    }

    return _state;
  }

  /// Replace state (e.g., after loading) and reset timing.
  void replaceState(GameState newState) {
    _state = newState;
    _stateController.add(newState);
    _lastTickMs = _now().millisecondsSinceEpoch;
  }

  // Developer-only helpers mirroring original cheat panel actions.
  void cheatCompleteTask() {
    if (!cheatsEnabled) return;
    _state = progressService.forceTaskComplete(_state);
    _stateController.add(_state);
  }

  void cheatCompleteQuest() {
    if (!cheatsEnabled) return;
    _state = progressService.forceQuestComplete(_state);
    _stateController.add(_state);
  }

  void cheatCompletePlot() {
    if (!cheatsEnabled) return;
    _state = progressService.forcePlotComplete(_state);
    _stateController.add(_state);
  }

  int _computeDelta() {
    final nowMs = _now().millisecondsSinceEpoch;
    final last = _lastTickMs;
    _lastTickMs = nowMs;
    if (last == null) return 0;
    final delta = nowMs - last;
    if (delta < 0) return 0;
    return delta;
  }
}
