import 'dart:typed_data';

import 'package:crypto/crypto.dart';
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';

import 'io/discovery_stub.dart'
    if (dart.library.io) 'io/discovery_io.dart'
    as platform;
import 'wl_parser.dart';

/// The main entry point for loading Wolfenstein 3D data.
///
/// This class provides high-level methods to either scan a local filesystem
/// (on supported platforms) or load data directly from memory (Web/Flutter).
class WolfensteinLoader {
  /// Scans [directoryPath] for Wolfenstein data files.
  ///
  /// On Web, this will throw an [UnsupportedError]. On Desktop/Mobile, it will
  /// attempt to identify and load all valid game versions found in the path.
  static Future<Map<GameVersion, WolfensteinData>> discover({
    String? directoryPath,
    bool recursive = false,
  }) {
    return platform.discoverInDirectory(
      directoryPath: directoryPath,
      recursive: recursive,
    );
  }

  /// Manually loads game data from provided [ByteData] buffers.
  ///
  /// Use this for Web or Flutter assets where automated directory scanning
  /// is not possible. It automatically detects the [DataVersion] (v1.0, v1.4, etc.)
  /// by hashing the [vswap] buffer.
  ///
  /// Supply [registryOverride] to use a fully custom [AssetRegistry] instead
  /// of the built-in version-detected registry. This is the primary extension
  /// point for modded or custom asset packs.
  static WolfensteinData loadFromBytes({
    required GameVersion version,
    required ByteData? vswap,
    required ByteData? mapHead,
    required ByteData? gameMaps,
    required ByteData? vgaDict,
    required ByteData? vgaHead,
    required ByteData? vgaGraph,
    required ByteData? audioHed,
    required ByteData? audioT,
    AssetRegistry? registryOverride,
  }) {
    // 1. Validation Check
    final Map<String, ByteData?> files = {
      'VSWAP': vswap,
      'MAPHEAD': mapHead,
      'GAMEMAPS': gameMaps,
      'VGADICT': vgaDict,
      'VGAHEAD': vgaHead,
      'VGAGRAPH': vgaGraph,
      'AUDIOHED': audioHed,
      'AUDIOT': audioT,
    };

    final missing = files.entries
        .where((e) => e.value == null)
        .map((e) => "${e.key}.${version.fileExtension}")
        .toList();

    if (missing.isNotEmpty) {
      throw ArgumentError(
        'Cannot load ${version.name}: Missing files: ${missing.join(", ")}',
      );
    }

    // 2. Identify identity for specialised parsing (e.g., MAPTEMP vs GAMEMAPS).
    final vswapBytes = vswap!.buffer.asUint8List(
      vswap.offsetInBytes,
      vswap.lengthInBytes,
    );
    final hash = md5.convert(vswapBytes).toString();
    final dataIdentity = DataVersion.fromChecksum(hash);

    // 3. Pass-through to parser with the detected identity and optional override.
    return WLParser.load(
      version: version,
      dataIdentity: dataIdentity,
      vswap: vswap,
      mapHead: mapHead!,
      gameMaps: gameMaps!,
      vgaDict: vgaDict!,
      vgaHead: vgaHead!,
      vgaGraph: vgaGraph!,
      audioHed: audioHed!,
      audioT: audioT!,
      registryOverride: registryOverride,
    );
  }
}
