import 'dart:io';

const String hookStartMarker = '// flutter_scene:init:start';
const String hookEndMarker = '// flutter_scene:init:end';

const String _hookSnippet =
    '''
$hookStartMarker
    // Import .glb scenes under assets/ as DataAssets, loadable by source path
    // with loadScene (and hot-reloadable). A no-op when there are no scenes.
    buildScenes(
      buildInput: input,
      buildOutput: output,
      assetMode: SceneAssetMode.dataAssetsRequired,
    );
    // Compile .fmat materials under assets/ as DataAssets, loadable by source
    // path with loadFmatMaterial (and hot-reloadable). A no-op when there are
    // no materials.
    await buildMaterials(
      buildInput: input,
      buildOutput: output,
      assetMode: MaterialAssetMode.dataAssetsRequired,
    );
$hookEndMarker''';

const String generatedBuildHook =
    '''
import 'package:flutter_scene/build_hooks.dart';
import 'package:hooks/hooks.dart';

void main(List<String> args) async {
  await build(args, (input, output) async {
$_hookSnippet
  });
}
''';

const String manualInstallInstructions =
    '''
Add this call to your existing hook/build.dart:

$_hookSnippet

The generated hook requires Flutter DataAssets support. On supported Flutter
master builds, run:

  flutter config --enable-dart-data-assets

If your Flutter toolchain does not recognize that setting, switch to a Flutter
master channel build. DataAssets mode intentionally does not add legacy
flutter.assets entries.
''';

enum InitHookStatus { created, updated, alreadyConfigured, needsManualInstall }

final class InitHookResult {
  const InitHookResult(this.status, this.message);

  final InitHookStatus status;
  final String message;
}

Future<InitHookResult> installFlutterSceneBuildHook({
  Directory? projectRoot,
}) async {
  final root = projectRoot ?? Directory.current;
  final hookDirectory = Directory.fromUri(root.uri.resolve('hook/'));
  final hookFile = File.fromUri(hookDirectory.uri.resolve('build.dart'));

  if (!hookFile.existsSync()) {
    hookDirectory.createSync(recursive: true);
    hookFile.writeAsStringSync(generatedBuildHook);
    return InitHookResult(
      InitHookStatus.created,
      'Created hook/build.dart for flutter_scene DataAssets.',
    );
  }

  final contents = hookFile.readAsStringSync();
  if (contents.contains(hookStartMarker) && contents.contains(hookEndMarker)) {
    final updated = contents.replaceRange(
      contents.indexOf(hookStartMarker),
      contents.indexOf(hookEndMarker) + hookEndMarker.length,
      _hookSnippet.trimRight(),
    );
    if (updated == contents) {
      return InitHookResult(
        InitHookStatus.alreadyConfigured,
        'hook/build.dart is already configured for flutter_scene DataAssets.',
      );
    }
    hookFile.writeAsStringSync(updated);
    return InitHookResult(
      InitHookStatus.updated,
      'Updated the flutter_scene managed block in hook/build.dart.',
    );
  }

  if (contents.contains('buildMaterials(') &&
      contents.contains('MaterialAssetMode.dataAssetsRequired')) {
    return InitHookResult(
      InitHookStatus.alreadyConfigured,
      'hook/build.dart already appears to require flutter_scene DataAssets.',
    );
  }

  return InitHookResult(
    InitHookStatus.needsManualInstall,
    'hook/build.dart already exists and was not generated by flutter_scene.\n\n'
    '$manualInstallInstructions',
  );
}
