import 'package:block_seasons/game/engine/game_engine.dart';
import 'package:block_seasons/game/models/stage.dart';
import 'package:flutter_test/flutter_test.dart';

StageConfig _stage() => StageConfig.fromJson({
      'id': 'b_test',
      'seed': 1,
      'moveLimit': 20,
      'preset': [
        {'x': 0, 'y': 0, 't': 'filled', 'c': 3},
        {'x': 1, 'y': 0, 't': 'filled', 'c': 4},
      ],
      'objectives': [
        {'type': 'reachScore', 'target': 100000},
      ],
      'stars': {
        'two': {'movesLeft': 5},
        'three': {'movesLeft': 10},
      },
    });

void main() {
  test('useHammer empties a filled cell without scoring or spending a move', () {
    final e = GameEngine(_stage());
    final score0 = e.score;
    final moves0 = e.movesUsed;

    expect(e.grid.isOccupied(0, 0), isTrue);
    final ok = e.useHammer(0, 0);

    expect(ok, isTrue);
    expect(e.grid.isOccupied(0, 0), isFalse);
    expect(e.score, score0, reason: 'no points from a booster');
    expect(e.movesUsed, moves0, reason: 'no move spent');
  });

  test('useHammer on an empty cell returns false and changes nothing', () {
    final e = GameEngine(_stage());
    expect(e.grid.isOccupied(5, 5), isFalse);
    expect(e.useHammer(5, 5), isFalse);
    expect(e.grid.isOccupied(5, 5), isFalse);
  });

  test('useHammer is rejected once the stage is won or lost', () {
    final e = GameEngine(_stage());
    e.declineAndLose();
    expect(e.useHammer(0, 0), isFalse);
  });

  test('useShuffle replaces the tray without spending a move or scoring', () {
    final e = GameEngine(_stage());
    final before = List.of(e.tray);
    final score0 = e.score;
    final moves0 = e.movesUsed;

    final ok = e.useShuffle();

    expect(ok, isTrue);
    expect(e.tray.length, before.length);
    expect(e.score, score0);
    expect(e.movesUsed, moves0);
  });

  test('useShuffle is rejected after the attempt finishes', () {
    final e = GameEngine(_stage());
    e.declineAndLose();
    expect(e.useShuffle(), isFalse);
  });

  test('useLineBomb(row:) empties that row, no scoring or move', () {
    final e = GameEngine(_stage()); // row 0 has cells at x=0,1
    final score0 = e.score;
    final moves0 = e.movesUsed;

    final ok = e.useLineBomb(row: 0);

    expect(ok, isTrue);
    for (var x = 0; x < 8; x++) {
      expect(e.grid.isOccupied(x, 0), isFalse, reason: 'col $x');
    }
    expect(e.score, score0);
    expect(e.movesUsed, moves0);
  });

  test('useLineBomb(col:) empties that column', () {
    final e = GameEngine(_stage()); // (0,0) filled
    expect(e.useLineBomb(col: 0), isTrue);
    for (var y = 0; y < 8; y++) {
      expect(e.grid.isOccupied(0, y), isFalse, reason: 'row $y');
    }
  });

  test('useLineBomb requires exactly one of row/col', () {
    final e = GameEngine(_stage());
    expect(e.useLineBomb(), isFalse);
    expect(e.useLineBomb(row: 0, col: 0), isFalse);
  });

  test('useLineBomb is rejected after the attempt finishes', () {
    final e = GameEngine(_stage());
    e.declineAndLose();
    expect(e.useLineBomb(row: 0), isFalse);
  });
}
