import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Data extends ChangeNotifier {
  // Configuration available parameters
  List _availableParameters = ['level', 'size', 'colors', 'skin'];
  List get availableParameters => _availableParameters;

  // Configuration available values
  List _availableLevelValues = ['easy', 'medium', 'hard', 'nightmare'];
  List _availableSizeValues = ['small', 'medium', 'large', 'extra'];
  List _availableColorsValues = ['5', '6', '7', '8'];
  List _availableSkinValues = ['default', 'retro', 'numbers', 'symbols'];

  List get availableLevelValues => _availableLevelValues;
  List get availableSizeValues => _availableSizeValues;
  List get availableColorsValues => _availableColorsValues;
  List get availableSkinValues => _availableSkinValues;

  // Application default configuration
  String _parameterLevel = '';
  String _parameterLevelDefault = 'medium';
  String _parameterSize = '';
  String _parameterSizeDefault = 'medium';
  String _parameterColors = '';
  String _parameterColorsDefault = '6';
  String _parameterSkin = '';
  String _parameterSkinDefault = 'default';

  // Application current configuration
  String get parameterLevel => _parameterLevel;
  String get parameterSize => _parameterSize;
  String get parameterColors => _parameterColors;
  String get parameterSkin => _parameterSkin;

  // Game data
  bool _gameIsRunning = false;
  bool _animationInProgress = false;
  bool _gameWon = false;
  int _boardSize = 0;
  int _colorsCount = 0;
  int _movesCount = 0;
  int _maxMovesCount = 0;
  List _cells = [];

  int _progress = 0;
  int _progressTotal = 0;
  int _progressDelta = 0;

  void updateParameterLevel(String parameterLevel) {
    _parameterLevel = parameterLevel;
    notifyListeners();
  }

  void updateParameterSize(String parameterSize) {
    _parameterSize = parameterSize;
    updateBoardSize(getBoardSizeFromParameter(parameterSize));
    notifyListeners();
  }

  void updateParameterColors(String parameterColors) {
    _parameterColors = parameterColors;
    updateColorsCount(getColorsCountFromParameter(parameterColors));
    notifyListeners();
  }

  void updateParameterSkin(String parameterSkin) {
    _parameterSkin = parameterSkin;
    notifyListeners();
  }

  String getParameterValue(String parameterCode) {
    switch (parameterCode) {
      case 'level':
        {
          return _parameterLevel;
        }
      case 'size':
        {
          return _parameterSize;
        }
      case 'colors':
        {
          return _parameterColors;
        }
      case 'skin':
        {
          return _parameterSkin;
        }
    }
    return '';
  }

  List getParameterAvailableValues(String parameterCode) {
    switch (parameterCode) {
      case 'level':
        {
          return _availableLevelValues;
        }
      case 'size':
        {
          return _availableSizeValues;
        }
      case 'colors':
        {
          return _availableColorsValues;
        }
      case 'skin':
        {
          return _availableSkinValues;
        }
    }
    return [];
  }

  void setParameterValue(String parameterCode, String parameterValue) async {
    switch (parameterCode) {
      case 'level':
        {
          updateParameterLevel(parameterValue);
        }
        break;
      case 'size':
        {
          updateParameterSize(parameterValue);
        }
        break;
      case 'colors':
        {
          updateParameterColors(parameterValue);
        }
        break;
      case 'skin':
        {
          updateParameterSkin(parameterValue);
        }
        break;
    }
    final prefs = await SharedPreferences.getInstance();
    prefs.setString(parameterCode, parameterValue);
  }

  void initParametersValues() async {
    final prefs = await SharedPreferences.getInstance();
    setParameterValue('level', prefs.getString('level') ?? _parameterLevelDefault);
    setParameterValue('size', prefs.getString('size') ?? _parameterSizeDefault);
    setParameterValue('colors', prefs.getString('colors') ?? _parameterColorsDefault);
    setParameterValue('skin', prefs.getString('skin') ?? _parameterSkinDefault);
  }

  int getBoardSizeFromParameter(String parameterSize) {
    switch (parameterSize) {
      case 'small':
        {
          return 6;
        }
      case 'medium':
        {
          return 10;
        }
      case 'large':
        {
          return 14;
        }
      case 'extra':
        {
          return 20;
        }
    }
    return getBoardSizeFromParameter(_parameterSizeDefault);
  }

  int getColorsCountFromParameter(String parameterColors) {
    switch (parameterColors) {
      case '5':
        {
          return 5;
        }
      case '6':
        {
          return 6;
        }
      case '7':
        {
          return 7;
        }
      case '8':
        {
          return 8;
        }
    }
    return getColorsCountFromParameter(_parameterColorsDefault);
  }

  int getMovesCountLimitDeltaFromLevelParameter(String parameterLevel) {
    switch (parameterLevel) {
      case 'easy':
        {
          return 5;
        }
      case 'medium':
        {
          return 3;
        }
      case 'hard':
        {
          return 1;
        }
      case 'nightmare':
        {
          return -1;
        }
    }
    return getMovesCountLimitDeltaFromLevelParameter(_parameterLevelDefault);
  }

  int get boardSize => _boardSize;
  void updateBoardSize(int boardSize) {
    _boardSize = boardSize;
    _progressTotal = boardSize * boardSize;
  }

  int get colorsCount => _colorsCount;
  void updateColorsCount(int colorsCount) {
    _colorsCount = colorsCount;
  }

  List get cells => _cells;
  void updateCells(List cells) {
    _cells = cells;
    notifyListeners();
  }

  updateCellValue(int col, int row, int value) {
    _cells[row][col].value = value;
    notifyListeners();
  }

  int getFirstCellValue() {
    return _cells[0][0].value;
  }

  int getCellValue(int col, int row) {
    return _cells[row][col].value;
  }

  int get movesCount => _movesCount;
  void updateMovesCount(int movesCount) {
    _movesCount = movesCount;
    notifyListeners();
  }

  void incrementMovesCount() {
    updateMovesCount(movesCount + 1);
  }

  int get maxMovesCount => _maxMovesCount;
  void updateMaxMovesCount(int maxMovesCount) {
    _maxMovesCount = maxMovesCount;
  }

  int get progress => _progress;
  int get progressTotal => _progressTotal;
  int get progressDelta => _progressDelta;
  void updateProgress(int progress) {
    _progress = progress;
    notifyListeners();
  }

  void updateProgressTotal(int progressTotal) {
    _progressTotal = progressTotal;
    notifyListeners();
  }

  void updateProgressDelta(int progressDelta) {
    _progressDelta = progressDelta;
    notifyListeners();
  }

  bool get gameIsRunning => _gameIsRunning;
  void updateGameIsRunning(bool gameIsRunning) {
    _gameIsRunning = gameIsRunning;
    notifyListeners();
  }

  bool isGameFinished() {
    return _gameWon;
  }

  bool get gameWon => _gameWon;
  void updateGameWon(bool gameWon) {
    _gameWon = gameWon;
    notifyListeners();
  }

  bool get animationInProgress => _animationInProgress;
  void updateAnimationInProgress(bool animationInProgress) {
    _animationInProgress = animationInProgress;
    notifyListeners();
  }

  void resetGame() {
    _gameIsRunning = false;
    _gameWon = false;
    _movesCount = 0;
    _maxMovesCount = 0;
    _progress = 0;
    notifyListeners();
  }
}