// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/android.dart';
import 'package:flutter_tools/src/build_system/targets/deferred_components.dart';

import '../../../src/common.dart';
import '../../../src/context.dart';

// These tests perform a simple check to verify if the check/task was executed at all.
// Detailed per-check tests are in android/deferred_components_setup_validator_test.dart.
void main() {
  late FileSystem fileSystem;
  late BufferLogger logger;

  setUp(() {
    logger = BufferLogger.test();
    fileSystem = MemoryFileSystem.test();
  });

  testUsingContext('checkAppAndroidManifestComponentLoadingUnitMapping checks runs', () async {
    final environment = Environment.test(
      fileSystem.currentDirectory,
      outputDir: fileSystem.directory('out')..createSync(),
      buildDir: fileSystem.directory('build')..createSync(),
      projectDir: fileSystem.directory('project')..createSync(),
      defines: <String, String>{kDeferredComponents: 'true'},
      artifacts: Artifacts.test(),
      processManager: FakeProcessManager.empty(),
      fileSystem: fileSystem,
      logger: logger,
    );
    environment.buildDir.createSync(recursive: true);
    const androidAot = AndroidAot(TargetPlatform.android_arm64, BuildMode.release);
    const androidAotBundle = AndroidAotBundle(androidAot);
    final androidDefBundle = AndroidAotDeferredComponentsBundle(androidAotBundle);
    final validatorTarget = DeferredComponentsGenSnapshotValidatorTarget(
      deferredComponentsDependencies: <AndroidAotDeferredComponentsBundle>[androidDefBundle],
      nonDeferredComponentsDependencies: <Target>[],
      title: 'test checks',
      exitOnFail: false,
    );

    await validatorTarget.build(environment);

    // We check the inputs to determine if the task was executed.
    expect(validatorTarget.validator!.inputs.length, 3);
    expect(validatorTarget.validator!.inputs[0].path, 'project/pubspec.yaml');
    expect(
      validatorTarget.validator!.inputs[1].path,
      'project/android/app/src/main/AndroidManifest.xml',
    );
  });

  testUsingContext('checkAgainstLoadingUnitsCache checks runs', () async {
    final environment = Environment.test(
      fileSystem.currentDirectory,
      outputDir: fileSystem.directory('out')..createSync(),
      buildDir: fileSystem.directory('build')..createSync(),
      projectDir: fileSystem.directory('project')..createSync(),
      defines: <String, String>{kDeferredComponents: 'true'},
      artifacts: Artifacts.test(),
      processManager: FakeProcessManager.empty(),
      fileSystem: fileSystem,
      logger: logger,
    );
    environment.buildDir.createSync(recursive: true);
    const androidAot = AndroidAot(TargetPlatform.android_arm64, BuildMode.release);
    const androidAotBundle = AndroidAotBundle(androidAot);
    final androidDefBundle = AndroidAotDeferredComponentsBundle(androidAotBundle);
    final validatorTarget = DeferredComponentsGenSnapshotValidatorTarget(
      deferredComponentsDependencies: <AndroidAotDeferredComponentsBundle>[androidDefBundle],
      nonDeferredComponentsDependencies: <Target>[],
      title: 'test checks',
      exitOnFail: false,
    );

    await validatorTarget.build(environment);

    // We check the inputs to determine if the task was executed.
    expect(validatorTarget.validator!.inputs.length, 3);
    expect(
      validatorTarget.validator!.inputs[2].path,
      'project/deferred_components_loading_units.yaml',
    );
  });

  testUsingContext('writeLoadingUnitsCache task runs', () async {
    final environment = Environment.test(
      fileSystem.currentDirectory,
      outputDir: fileSystem.directory('out')..createSync(),
      buildDir: fileSystem.directory('build')..createSync(),
      projectDir: fileSystem.directory('project')..createSync(),
      defines: <String, String>{kDeferredComponents: 'true'},
      artifacts: Artifacts.test(),
      processManager: FakeProcessManager.empty(),
      fileSystem: fileSystem,
      logger: logger,
    );
    environment.buildDir.createSync(recursive: true);
    const androidAot = AndroidAot(TargetPlatform.android_arm64, BuildMode.release);
    const androidAotBundle = AndroidAotBundle(androidAot);
    final androidDefBundle = AndroidAotDeferredComponentsBundle(androidAotBundle);
    final validatorTarget = DeferredComponentsGenSnapshotValidatorTarget(
      deferredComponentsDependencies: <AndroidAotDeferredComponentsBundle>[androidDefBundle],
      nonDeferredComponentsDependencies: <Target>[],
      title: 'test checks',
      exitOnFail: false,
    );

    await validatorTarget.build(environment);

    // We check the inputs to determine if the task was executed.
    expect(validatorTarget.validator!.outputs.length, 1);
    expect(
      validatorTarget.validator!.outputs[0].path,
      'project/deferred_components_loading_units.yaml',
    );
  });
}
