import 'package:momomotus/config/default_game_settings.dart';
import 'package:momomotus/data/fetch_data_helper.dart';
import 'package:momomotus/models/settings/settings_game.dart';
import 'package:momomotus/models/settings/settings_global.dart';
import 'package:momomotus/utils/tools.dart';

class Game {
  Game({
    // Settings
    required this.gameSettings,
    required this.globalSettings,

    // State
    this.isRunning = false,
    this.isStarted = false,
    this.animationInProgress = false,

    // Base data
    required this.word,
    required this.dictionary,

    // Game data
    this.currentGuess = '',
    this.foundLetters = '',
    required this.guesses,
    this.foundWord = false,
  });

  // Settings
  final GameSettings gameSettings;
  final GlobalSettings globalSettings;

  // State
  bool isRunning;
  bool isStarted;
  bool animationInProgress;

  // Base data
  final String word;
  final List<String> dictionary;

  // Game data
  String currentGuess;
  String foundLetters;
  List<String> guesses;
  bool foundWord;

  factory Game.createEmpty() {
    return Game(
      // Settings
      gameSettings: GameSettings.createDefault(),
      globalSettings: GlobalSettings.createDefault(),
      // Base data
      word: '',
      dictionary: [],
      // Game data
      guesses: [],
    );
  }

  factory Game.createNew({
    GameSettings? gameSettings,
    GlobalSettings? globalSettings,
  }) {
    final GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
    final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();

    final String pickedWord = FetchDataHelper().getRandomWord(
      lang: newGameSettings.lang,
      length: newGameSettings.length,
      level: newGameSettings.level,
    );

    final List<String> dictionary = FetchDataHelper().getDictionary(
      lang: newGameSettings.lang,
      length: newGameSettings.length,
    );

    // Starts with first letter revealed
    final String foundLetters = pickedWord.substring(0, 1).padRight(pickedWord.length, ' ');

    return Game(
      // Settings
      gameSettings: newGameSettings,
      globalSettings: newGlobalSettings,
      // State
      isRunning: true,
      // Base data
      word: pickedWord,
      dictionary: dictionary,
      // Game data
      foundLetters: foundLetters,
      guesses: [],
    );
  }

  bool get canBeResumed => isStarted && !isFinished;
  bool get gameWon => isRunning && isStarted && isFinished;
  bool get isFinished {
    if (foundWord || (guesses.length >= DefaultGameSettings.maxGuessesCount)) {
      return true;
    }

    return false;
  }

  bool checkWordIsValid(String candidate) {
    final int length = int.parse(gameSettings.length);

    return (word.length == length) &&
        (candidate.length == length) &&
        dictionary.contains(candidate);
  }

  void dump() {
    printlog('');
    printlog('## Current game dump:');
    printlog('');
    printlog('$Game:');
    printlog('  Settings');
    gameSettings.dump();
    globalSettings.dump();
    printlog('  State');
    printlog('    isRunning: $isRunning');
    printlog('    isStarted: $isStarted');
    printlog('    isFinished: $isFinished');
    printlog('    animationInProgress: $animationInProgress');
    printlog('  Base data');
    printlog('    word: $word');
    printlog('    dictionary: ${dictionary.length}');
    printlog('  Game data');
    printlog('    currentGuess: $currentGuess');
    printlog('    foundLetters: $foundLetters');
    printlog('    guesses: $guesses');
    printlog('    foundWord: $foundWord');
    printlog('');
  }

  @override
  String toString() {
    return '$Game(${toJson()})';
  }

  Map<String, dynamic>? toJson() {
    return <String, dynamic>{
      // Settings
      'gameSettings': gameSettings.toJson(),
      'globalSettings': globalSettings.toJson(),
      // State
      'isRunning': isRunning,
      'isStarted': isStarted,
      'isFinished': isFinished,
      'animationInProgress': animationInProgress,
      // Base data
      'word': word,
      'dictionary': dictionary,
      // Game data
      'currentGuess': currentGuess,
      'foundLetters': foundLetters,
      'guesses': guesses,
      'foundWord': foundWord,
    };
  }
}