import 'dart:convert';
import 'dart:io';

const _pinnedMdkVersion = '0.37.0';

Future<void> main(List<String> arguments) async {
  try {
    final projectRoot = _parseProjectRoot(arguments);
    await _invalidateStaleFvpAndroidSdk(projectRoot);
  } on FormatException catch (error) {
    stderr.writeln('error: ${error.message}');
    exitCode = 2;
  } on FileSystemException catch (error) {
    stderr.writeln('error: ${error.message}');
    exitCode = 1;
  } on StateError catch (error) {
    stderr.writeln('error: ${error.message}');
    exitCode = 1;
  }
}

String _parseProjectRoot(List<String> arguments) {
  if (arguments.isEmpty) return _defaultProjectRoot;
  if (arguments.length == 2 && arguments.first == '--project-root') {
    return Directory(arguments.last).absolute.path;
  }
  throw const FormatException(
    'Usage: dart scripts/prepare_fvp_android_deps.dart '
    '[--project-root <path>]',
  );
}

Future<void> _invalidateStaleFvpAndroidSdk(String projectRoot) async {
  final packageConfigFile = File(
    '$projectRoot${Platform.pathSeparator}.dart_tool'
    '${Platform.pathSeparator}package_config.json',
  );
  if (!await packageConfigFile.exists()) {
    throw StateError(
      'package_config.json not found: ${packageConfigFile.path} '
      '(run flutter pub get first)',
    );
  }

  final packageConfig = jsonDecode(await packageConfigFile.readAsString());
  if (packageConfig is! Map<String, dynamic>) {
    throw StateError('Invalid package_config.json root object');
  }
  final packages = packageConfig['packages'];
  if (packages is! List) {
    throw StateError('Invalid package_config.json packages list');
  }

  Map<String, dynamic>? fvpPackage;
  for (final package in packages) {
    if (package is Map<String, dynamic> && package['name'] == 'fvp') {
      fvpPackage = package;
      break;
    }
  }
  if (fvpPackage == null) {
    throw StateError('Package fvp not found in package_config.json');
  }

  final rootUriValue = fvpPackage['rootUri'];
  if (rootUriValue is! String || rootUriValue.isEmpty) {
    throw StateError('Package fvp has an invalid rootUri');
  }
  final fvpRootUri = packageConfigFile.uri.resolve(rootUriValue);
  if (fvpRootUri.scheme != 'file') {
    throw StateError('Unsupported fvp rootUri: $rootUriValue');
  }

  final fvpRootDirectory = Directory.fromUri(fvpRootUri);
  final fvpAndroidDirectory = Directory(
    '${fvpRootDirectory.path}${Platform.pathSeparator}android',
  );
  if (!await fvpAndroidDirectory.exists()) {
    throw StateError(
      'fvp Android directory not found: ${fvpAndroidDirectory.path}',
    );
  }

  final sdkDirectory = Directory(
    '${fvpAndroidDirectory.path}${Platform.pathSeparator}mdk-sdk',
  );
  final sdkArchive = File(
    '${fvpAndroidDirectory.path}${Platform.pathSeparator}mdk-sdk-android.7z',
  );
  final versionMarker = File(
    '${fvpAndroidDirectory.path}'
    '${Platform.pathSeparator}.smplayer-mdk-version',
  );
  final findMdkFile = File(
    '${sdkDirectory.path}${Platform.pathSeparator}lib'
    '${Platform.pathSeparator}cmake'
    '${Platform.pathSeparator}FindMDK.cmake',
  );

  final installedVersion = await versionMarker.exists()
      ? (await versionMarker.readAsString()).trim()
      : '';
  final sdkIsReady =
      installedVersion == _pinnedMdkVersion && await findMdkFile.exists();
  if (sdkIsReady) {
    stdout.writeln(
      '[fvp-android] mdk-sdk v$_pinnedMdkVersion is ready: '
      '${sdkDirectory.path}',
    );
    return;
  }

  final displayVersion = installedVersion.isEmpty
      ? 'unknown'
      : installedVersion;
  stdout.writeln(
    '[fvp-android] Invalidating cached mdk-sdk v$displayVersion; '
    'the next Flutter build will download v$_pinnedMdkVersion.',
  );
  if (await sdkDirectory.exists()) {
    await sdkDirectory.delete(recursive: true);
  }
  if (await sdkArchive.exists()) {
    await sdkArchive.delete();
  }
  await versionMarker.writeAsString(_pinnedMdkVersion, flush: true);
}

String get _defaultProjectRoot =>
    File.fromUri(Platform.script).parent.parent.absolute.path;
