import 'dart:async';
import 'dart:math';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:image/image.dart' as imglib;
import 'package:puzzlegame/entities/moving_tile.dart';
import 'package:puzzlegame/entities/tile.dart';
import 'package:puzzlegame/provider/data.dart';

class GameUtils {
  static String getImageAssetName(String imageCode) {
    return 'assets/images/' + imageCode + '.png';
  }

  static startGame(Data myProvider, String imageCode) {
    myProvider.updateIsShufflingBoard(true);
    myProvider.updateSelectedImage(imageCode);

    new Timer(new Duration(seconds: 1), () {
      GameUtils.splitImageInTiles(myProvider);
    });
  }

  static startRandomGame(Data myProvider) {
    List sizes = [3, 4, 5];
    sizes.shuffle();
    myProvider.updateTilesCount(sizes[0]);

    List images = myProvider.availableImages;
    images.shuffle();

    startGame(myProvider, images[0]);
  }

  static Future<void> resetGame(Data myProvider) async {
    myProvider.resetSelectedImage();
    myProvider.updateIsTipImageDisplayed(false);
  }

  static bool checkTilesetIsCleared(List<MovingTile> tiles) {
    for (Tile tile in tiles) {
      if (!tile.isCorrect()) {
        return false;
      }
    }
    return true;
  }

  static List<MovingTile> shuffleMovingTiles(List<MovingTile> tiles) {
    var random = new Random();
    int tilesCount = tiles.length;

    for (int i = 0; i < (10 * tilesCount); i++) {
      int indexTile1 = random.nextInt(tilesCount);
      int indexTile2 = random.nextInt(tilesCount);

      MovingTile swap = tiles[indexTile1];
      tiles[indexTile1] = tiles[indexTile2];
      tiles[indexTile2] = swap;

      int swapCol = tiles[indexTile1].currentCol;
      tiles[indexTile1].currentCol = tiles[indexTile2].currentCol;
      tiles[indexTile2].currentCol = swapCol;

      int swapRow = tiles[indexTile1].currentRow;
      tiles[indexTile1].currentRow = tiles[indexTile2].currentRow;
      tiles[indexTile2].currentRow = swapRow;
    }

    return tiles;
  }

  static Future<void> splitImageInTiles(Data myProvider) async {
    String imageAsset = getImageAssetName(myProvider.selectedImage);
    Uint8List imageData = (await rootBundle.load(imageAsset)).buffer.asUint8List();

    imglib.Image image = imglib.decodeImage(imageData) ?? imglib.Image.fromBytes(1, 1, []);

    int x = 0, y = 0;
    int width = (image.width / myProvider.tilesCount).round();
    int height = (image.height / myProvider.tilesCount).round();

    List<MovingTile> tiles = [];
    for (int i = 0; i < myProvider.tilesCount; i++) {
      for (int j = 0; j < myProvider.tilesCount; j++) {
        Uint8List tileData = new Uint8List.fromList(imglib.encodeJpg(imglib.copyCrop(
          image,
          x,
          y,
          width,
          height,
        )));

        tiles.add(MovingTile(
          Image.memory(tileData),
          myProvider.tileImageSize,
          j,
          i,
          j,
          i,
        ));

        x += width;
      }
      x = 0;
      y += height;
    }

    myProvider.updateTiles(shuffleMovingTiles(tiles));
    myProvider.updateIsShufflingBoard(false);
  }
}