import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';

import 'package:solitaire/models/game/cell_location.dart';
import 'package:solitaire/models/game/game.dart';
import 'package:solitaire/models/settings/settings_game.dart';
import 'package:solitaire/models/settings/settings_global.dart';
import 'package:solitaire/utils/tools.dart';

part 'game_state.dart';

class GameCubit extends HydratedCubit<GameState> {
  GameCubit()
      : super(GameState(
          currentGame: Game.createEmpty(),
        ));

  void updateState(Game game) {
    emit(GameState(
      currentGame: game,
    ));
  }

  void refresh() {
    final Game game = Game(
      // Settings
      gameSettings: state.currentGame.gameSettings,
      globalSettings: state.currentGame.globalSettings,
      // State
      isRunning: state.currentGame.isRunning,
      isStarted: state.currentGame.isStarted,
      isFinished: state.currentGame.isFinished,
      animationInProgress: state.currentGame.animationInProgress,
      // Base data
      board: state.currentGame.board,
      // Game data
      movesCount: state.currentGame.movesCount,
      remainingPegsCount: state.currentGame.remainingPegsCount,
      allowedMovesCount: state.currentGame.allowedMovesCount,
    );
    // game.dump();

    updateState(game);
  }

  void startNewGame({
    required GameSettings gameSettings,
    required GlobalSettings globalSettings,
  }) {
    final Game newGame = Game.createNew(
      // Settings
      gameSettings: gameSettings,
      globalSettings: globalSettings,
    );

    newGame.dump();

    updateState(newGame);

    updateRemainingPegsCount(newGame.countRemainingPegs());
    updateAllowedMovesCount(newGame.countAllowedMoves());

    refresh();
  }

  void quitGame() {
    state.currentGame.isRunning = false;
    refresh();
  }

  void resumeSavedGame() {
    state.currentGame.isRunning = true;
    refresh();
  }

  void deleteSavedGame() {
    state.currentGame.isRunning = false;
    state.currentGame.isFinished = true;
    refresh();
  }

  void updatePegValue(CellLocation location, bool hasPeg) {
    state.currentGame.board.cells[location.row][location.col].hasPeg = hasPeg;
    refresh();
  }

  void incrementMovesCount() {
    state.currentGame.isStarted = true;
    state.currentGame.movesCount++;
    refresh();
  }

  void updateRemainingPegsCount(int count) {
    state.currentGame.remainingPegsCount = count;
    refresh();
  }

  void updateAllowedMovesCount(int count) {
    state.currentGame.allowedMovesCount = count;
    if (count == 0) {
      state.currentGame.isFinished = true;
    }

    refresh();
  }

  void move({
    required Game currentGame,
    required List<int> source,
    required List<int> target,
  }) {
    printlog('Move from $source to $target');
    final int sourceCol = source[0];
    final int sourceRow = source[1];
    final int targetCol = target[0];
    final int targetRow = target[1];

    final int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
    final int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();

    updatePegValue(CellLocation.go(sourceRow, sourceCol), false);
    updatePegValue(CellLocation.go(targetRow, targetCol), true);
    updatePegValue(CellLocation.go(middleRow, middleCol), false);

    incrementMovesCount();
    updateRemainingPegsCount(currentGame.countRemainingPegs());
    updateAllowedMovesCount(currentGame.countAllowedMoves());
  }

  @override
  GameState? fromJson(Map<String, dynamic> json) {
    final Game currentGame = json['currentGame'] as Game;

    return GameState(
      currentGame: currentGame,
    );
  }

  @override
  Map<String, dynamic>? toJson(GameState state) {
    return <String, dynamic>{
      'currentGame': state.currentGame.toJson(),
    };
  }
}