// Copyright 2013 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 'dart:async';
import 'dart:io' as io;

import 'package:flutter_migrate/src/base/context.dart';
import 'package:flutter_migrate/src/base/file_system.dart';
import 'package:flutter_migrate/src/base/io.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path; // flutter_ignore: package_path_import
import 'package:test_api/test_api.dart' // ignore: deprecated_member_use
    as test_package show test;
import 'package:test_api/test_api.dart' // ignore: deprecated_member_use
    hide
        test;

import 'test_utils.dart';

export 'package:test_api/test_api.dart' // ignore: deprecated_member_use
    hide
        isInstanceOf,
        test;

bool tryToDelete(FileSystemEntity fileEntity) {
  // This should not be necessary, but it turns out that
  // on Windows it's common for deletions to fail due to
  // bogus (we think) "access denied" errors.
  try {
    if (fileEntity.existsSync()) {
      fileEntity.deleteSync(recursive: true);
      return true;
    }
  } on FileSystemException catch (error) {
    // We print this so that it's visible in the logs, to get an idea of how
    // common this problem is, and if any patterns are ever noticed by anyone.
    // ignore: avoid_print
    print('Failed to delete ${fileEntity.path}: $error');
  }
  return false;
}

/// Gets the path to the root of the Flutter repository.
///
/// This will first look for a `FLUTTER_ROOT` environment variable. If the
/// environment variable is set, it will be returned. Otherwise, this will
/// deduce the path from `platform.script`.
String getFlutterRoot() {
  if (io.Platform.environment.containsKey('FLUTTER_ROOT')) {
    return io.Platform.environment['FLUTTER_ROOT']!;
  }

  Error invalidScript() => StateError(
      'Could not determine flutter_tools/ path from script URL (${io.Platform.script}); consider setting FLUTTER_ROOT explicitly.');

  Uri scriptUri;
  switch (io.Platform.script.scheme) {
    case 'file':
      scriptUri = io.Platform.script;
      break;
    case 'data':
      final RegExp flutterTools = RegExp(
          r'(file://[^"]*[/\\]flutter_tools[/\\][^"]+\.dart)',
          multiLine: true);
      final Match? match =
          flutterTools.firstMatch(Uri.decodeFull(io.Platform.script.path));
      if (match == null) {
        throw invalidScript();
      }
      scriptUri = Uri.parse(match.group(1)!);
      break;
    default:
      throw invalidScript();
  }

  final List<String> parts = path.split(fileSystem.path.fromUri(scriptUri));
  final int toolsIndex = parts.indexOf('flutter_tools');
  if (toolsIndex == -1) {
    throw invalidScript();
  }
  final String toolsPath = path.joinAll(parts.sublist(0, toolsIndex + 1));
  return path.normalize(path.join(toolsPath, '..', '..'));
}

String getMigratePackageRoot() {
  return io.Directory.current.path;
}

String getMigrateMain() {
  return fileSystem.path
      .join(getMigratePackageRoot(), 'bin', 'flutter_migrate.dart');
}

Future<ProcessResult> runMigrateCommand(List<String> args,
    {String? workingDirectory}) {
  final List<String> commandArgs = <String>['dart', 'run', getMigrateMain()];
  commandArgs.addAll(args);
  return processManager.run(commandArgs, workingDirectory: workingDirectory);
}

/// The tool overrides `test` to ensure that files created under the
/// system temporary directory are deleted after each test by calling
/// `LocalFileSystem.dispose()`.
@isTest
void test(
  String description,
  FutureOr<void> Function() body, {
  String? testOn,
  dynamic skip,
  List<String>? tags,
  Map<String, dynamic>? onPlatform,
  int? retry,
  Timeout? timeout,
}) {
  test_package.test(
    description,
    () async {
      addTearDown(() async {
        await fileSystem.dispose();
      });

      return body();
    },
    skip: skip,
    tags: tags,
    onPlatform: onPlatform,
    retry: retry,
    testOn: testOn,
    timeout: timeout,
    // We don't support "timeout"; see ../../dart_test.yaml which
    // configures all tests to have a 15 minute timeout which should
    // definitely be enough.
  );
}

/// Executes a test body in zone that does not allow context-based injection.
///
/// For classes which have been refactored to exclude context-based injection
/// or globals like [fs] or [platform], prefer using this test method as it
/// will prevent accidentally including these context getters in future code
/// changes.
///
/// For more information, see https://github.com/flutter/flutter/issues/47161
@isTest
void testWithoutContext(
  String description,
  FutureOr<void> Function() body, {
  String? testOn,
  dynamic skip,
  List<String>? tags,
  Map<String, dynamic>? onPlatform,
  int? retry,
  Timeout? timeout,
}) {
  return test(
    description,
    () async {
      return runZoned(body, zoneValues: <Object, Object>{
        contextKey: const _NoContext(),
      });
    },
    skip: skip,
    tags: tags,
    onPlatform: onPlatform,
    retry: retry,
    testOn: testOn,
    timeout: timeout,
    // We support timeout here due to the packages repo not setting default
    // timeout to 15min.
  );
}

/// An implementation of [AppContext] that throws if context.get is called in the test.
///
/// The intention of the class is to ensure we do not accidentally regress when
/// moving towards more explicit dependency injection by accidentally using
/// a Zone value in place of a constructor parameter.
class _NoContext implements AppContext {
  const _NoContext();

  @override
  T get<T>() {
    throw UnsupportedError('context.get<$T> is not supported in test methods. '
        'Use Testbed or testUsingContext if accessing Zone injected '
        'values.');
  }

  @override
  String get name => 'No Context';

  @override
  Future<V> run<V>({
    required FutureOr<V> Function() body,
    String? name,
    Map<Type, Generator>? overrides,
    Map<Type, Generator>? fallbacks,
    ZoneSpecification? zoneSpecification,
  }) async {
    return body();
  }
}

/// Matcher for functions that throw [AssertionError].
final Matcher throwsAssertionError = throwsA(isA<AssertionError>());
