// 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 'dart:async';
import 'dart:convert';
import 'dart:io' show Directory, File, Process, ProcessSignal;

import '../framework/devices.dart';
import '../framework/framework.dart';
import '../framework/task_result.dart';
import '../framework/utils.dart';

const String _messagePrefix = 'entrypoint:';
const String _entrypointName = 'entrypoint';

const String _dartCode = '''
import 'package:flutter/widgets.dart';

@pragma('vm:entry-point')
void main() {
  print('$_messagePrefix main');
  runApp(const ColoredBox(color: Color(0xffcc0000)));
}

@pragma('vm:entry-point')
void $_entrypointName() {
  print('$_messagePrefix $_entrypointName');
  runApp(const ColoredBox(color: Color(0xff00cc00)));
}
''';

const String _kotlinCode = '''
package com.example.entrypoint_dart_registrant

import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
  override fun getDartEntrypointFunctionName(): String {
    return "$_entrypointName"
  }
}
''';

Future<TaskResult> _runWithTempDir(Directory tempDir) async {
  const String testDirName = 'entrypoint_dart_registrant';
  final String testPath = '${tempDir.path}/$testDirName';
  await inDirectory(tempDir, () async {
    await flutter('create', options: <String>[
      '--platforms',
      'android',
      testDirName,
    ]);
  });
  final String mainPath = '${tempDir.path}/$testDirName/lib/main.dart';
  print(mainPath);
  File(mainPath).writeAsStringSync(_dartCode);
  final String activityPath =
      '${tempDir.path}/$testDirName/android/app/src/main/kotlin/com/example/entrypoint_dart_registrant/MainActivity.kt';
  File(activityPath).writeAsStringSync(_kotlinCode);
  final Device device = await devices.workingDevice;
  await device.unlock();
  final String entrypoint = await inDirectory(testPath, () async {
    // The problem only manifested when the dart plugin registrant was used
    // (which path_provider has).
    await flutter('pub', options: <String>['add', 'path_provider:2.0.9']);
    // The problem only manifested on release builds, so we test release.
    final Process process =
        await startFlutter('run', options: <String>['--release']);
    final Completer<String> completer = Completer<String>();
    final StreamSubscription<String> stdoutSub = process.stdout
        .transform<String>(const Utf8Decoder())
        .transform<String>(const LineSplitter())
        .listen((String line) async {
      print(line);
      if (line.contains(_messagePrefix)) {
        completer.complete(line);
      }
    });
    final String entrypoint = await completer.future;
    await stdoutSub.cancel();
    process.stdin.write('q');
    await process.stdin.flush();
    process.kill(ProcessSignal.sigint);
    return entrypoint;
  });
  if (entrypoint.contains('$_messagePrefix $_entrypointName')) {
    return TaskResult.success(null);
  } else {
    return TaskResult.failure('expected entrypoint:"$_entrypointName" but found:"$entrypoint"');
  }
}

/// Asserts that the custom entrypoint works in the presence of the dart plugin
/// registrant.
TaskFunction entrypointDartRegistrant() {
  return () async {
    final Directory tempDir =
        Directory.systemTemp.createTempSync('entrypoint_dart_registrant.');
    try {
      return await _runWithTempDir(tempDir);
    } finally {
      rmTree(tempDir);
    }
  };
}
