import 'dart:typed_data';

import 'package:test/test.dart';
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
import 'package:wolf_3d_dart/wolf_3d_input.dart';
import 'package:wolf_3d_dart/wolf_3d_renderer.dart';

void main() {
  group('Pushwall rasterization', () {
    test('active pushwall occludes the wall behind it while sliding', () {
      final wallGrid = _buildGrid();
      final objectGrid = _buildGrid();

      _fillBoundaries(wallGrid, 2);
      objectGrid[2][2] = MapObject.playerEast;

      wallGrid[2][4] = 1;
      objectGrid[2][4] = MapObject.pushwallTrigger;

      wallGrid[2][6] = 2;

      final engine = WolfEngine(
        data: WolfensteinData(
          version: GameVersion.shareware,
          dataVersion: DataVersion.unknown,
          registry: RetailAssetRegistry(),
          walls: [
            _solidSprite(1),
            _solidSprite(1),
            _solidSprite(2),
            _solidSprite(2),
          ],
          sprites: List.generate(436, (_) => _solidSprite(255)),
          sounds: [],
          adLibSounds: [],
          music: [],
          vgaImages: [],
          episodes: [
            Episode(
              name: 'Episode 1',
              levels: [
                WolfLevel(
                  name: 'Test Level',
                  wallGrid: wallGrid,
                  areaGrid: List.generate(64, (_) => List.filled(64, -1)),
                  objectGrid: objectGrid,
                  music: Music.level01,
                ),
              ],
            ),
          ],
        ),
        difficulty: Difficulty.medium,
        startingEpisode: 0,
        frameBuffer: FrameBuffer(64, 64),
        input: CliInput(),
        onGameWon: () {},
      );

      engine.init();

      final pushwall = engine.pushwallManager.pushwalls['4,2']!;
      pushwall
        ..dirX = 1
        ..dirY = 0
        ..offset = 0.5;
      engine.pushwallManager.activePushwall = pushwall;

      final frame = SoftwareRenderer().render(engine);
      final centerIndex =
          (frame.height ~/ 2) * frame.width + (frame.width ~/ 2);

      expect(frame.pixels[centerIndex], ColorPalette.vga32Bit[1]);
      expect(frame.pixels[centerIndex], isNot(ColorPalette.vga32Bit[2]));
    });
  });
}

SpriteMap _buildGrid() => List.generate(64, (_) => List.filled(64, 0));

void _fillBoundaries(SpriteMap grid, int wallId) {
  for (int i = 0; i < 64; i++) {
    grid[0][i] = wallId;
    grid[63][i] = wallId;
    grid[i][0] = wallId;
    grid[i][63] = wallId;
  }
}

Sprite _solidSprite(int colorIndex) {
  return Sprite(Uint8List.fromList(List.filled(64 * 64, colorIndex)));
}
