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';

void main() {
  group('Player movement parity', () {
    test('matches classic Wolf3D forward walking speed', () {
      final input = _HeldMoveInput(forward: true, backward: false);
      final engine = _buildEngine(input: input);

      engine.init();
      final startX = engine.player.x;

      engine.tick(const Duration(milliseconds: 1000));

      final movedForward = engine.player.x - startX;

      expect(
        movedForward,
        closeTo(PlayerLocomotionConstants.forwardTilesPerSecond, 0.01),
      );
    });

    test('matches classic Wolf3D backward walking speed', () {
      final input = _HeldMoveInput(forward: false, backward: true);
      final engine = _buildEngine(input: input);

      engine.init();
      final startX = engine.player.x;

      engine.tick(const Duration(milliseconds: 1000));

      final movedBackward = startX - engine.player.x;

      expect(
        movedBackward,
        closeTo(PlayerLocomotionConstants.backwardTilesPerSecond, 0.01),
      );
    });
  });
}

class _HeldMoveInput extends Wolf3dInput {
  _HeldMoveInput({required this.forward, required this.backward});

  final bool forward;
  final bool backward;

  @override
  void update() {
    isMovingForward = forward;
    isMovingBackward = backward;

    isTurningLeft = false;
    isTurningRight = false;
    isMapToggle = false;
    isInteracting = false;
    isFiring = false;
    isBack = false;
    requestedWeapon = null;
    menuTapX = null;
    menuTapY = null;
  }
}

WolfEngine _buildEngine({
  required Wolf3dInput input,
}) {
  final wallGrid = _buildGrid();
  final objectGrid = _buildGrid();
  _fillBoundaries(wallGrid, 2);
  objectGrid[20][20] = MapObject.playerEast;

  return 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: const [],
      adLibSounds: const [],
      music: const [],
      vgaImages: const [],
      episodes: [
        Episode(
          name: 'Episode 1',
          levels: [
            WolfLevel(
              name: 'Level 1',
              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: input,
    onGameWon: () {},
  );
}

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)));
}
