// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

@Tags(['integration4'])
library;

import 'package:build_runner/src/logging/build_log.dart';
import 'package:test/test.dart';

import '../common/common.dart';

const defaultTimeout = Timeout(Duration(minutes: 3));

void main() async {
  test('web compilers', () async {
    final pubspecs = await Pubspecs.load();
    final tester = BuildRunnerTester(pubspecs);

    tester.writeFixturePackage(FixturePackages.copyBuilder());

    tester.writePackage(
      name: 'root_pkg',
      dependencies: [
        'build',
        'build_config',
        'build_daemon',
        'build_modules',
        'build_runner',
        'build_web_compilers',
        'build_test',
        'scratch_space',
      ],
      pathDependencies: ['builder_pkg'],
      files: {
        'build.yaml': r'''
targets:
  $default:
    builders:
      build_web_compilers:entrypoint:
        generate_for:
          - web/main.dart
''',
        'lib/a.dart': '''
  final stringInA = 'string in a.dart';
''',
        'web/main.dart': '''
import 'package:root_pkg/a.dart';

void main() {
  print(stringInA);
}
''',
        'web/unused.dart': '',
      },
    );

    // Initial build AOT.
    await tester.run(
      'root_pkg',
      'dart run build_runner build --output web:build --force-aot',
    );

    // Initial build.
    await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build',
    );
    expect(
      tester.readFileTree('root_pkg/build')!.keys,
      containsAll([
        'main.dart.js',
        'main.digests',
        'main.dart.ddc_merged_metadata',
        'main.dart.bootstrap.js',
        'main.ddc.js.metadata',
        'main.ddc.js.map',
        'main.ddc.js',
        'main.dart',
        r'packages/$sdk/dev_compiler/amd/require.js',
        r'packages/$sdk/dev_compiler/ddc/ddc_module_loader.js',
        r'packages/$sdk/dev_compiler/web/dart_stack_trace_mapper.js',
      ]),
    );

    // DDC by default. Does not compile submodules into the root module.
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      isNot(contains('// Generated by dart2js')),
    );
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      isNot(contains('string in a.dart')),
    );

    // With dart2js. Does compile into a single file.
    await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build '
          '--define build_web_compilers:entrypoint=compiler=dart2js',
    );
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      contains('string in a.dart'),
    );
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      contains('// Generated by dart2js'),
    );

    // With dart2js + minify.
    await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build '
          '--define build_web_compilers:entrypoint=compiler=dart2js '
          '--define build_web_compilers:entrypoint=dart2js_args=["--minify"]',
    );
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      isNot(contains('// Generated by dart2js')),
    );
    expect(
      tester.read('root_pkg/build/main.dart.js'),
      contains('typeof dartMainRunner==="function"'),
    );

    // With dart2wasm.
    await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build '
          '--define build_web_compilers:entrypoint=compiler=dart2wasm',
    );
    expect(tester.readBytes('root_pkg/build/main.wasm'), isNotNull);

    // Introduce an error, build fails.
    tester.write('root_pkg/lib/a.dart', 'error');
    var output = await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build',
      expectExitCode: 1,
    );
    expect(output, contains(BuildLog.failurePattern));

    // Stop importing the file with the error, build succeeds.
    tester.write('root_pkg/web/main.dart', 'void main() {}');
    output = await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build',
    );
    expect(output, contains(BuildLog.successPattern));

    // With dart_source_cleanup unused source is removed.
    expect(tester.read('root_pkg/build/unused.dart'), '');
    await tester.run(
      'root_pkg',
      'dart run build_runner build --force-jit --output web:build '
          '--define=build_web_compilers:dart_source_cleanup=enabled=true',
    );
    expect(tester.read('root_pkg/build/unused.dart'), null);
  }, timeout: defaultTimeout);
}
