// Copyright 2016 The Chromium 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:math' as math;

import '../application_package.dart';
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../base/process_manager.dart';
import '../build_info.dart';
import '../device.dart';
import '../flx.dart' as flx;
import '../globals.dart';
import '../protocol_discovery.dart';
import 'ios_workflow.dart';
import 'mac.dart';

const String _xcrunPath = '/usr/bin/xcrun';

/// Test device created by Flutter when no other device is available.
const String _kFlutterTestDeviceSuffix = '(Flutter)';

class IOSSimulators extends PollingDeviceDiscovery {
  IOSSimulators() : super('iOS simulators');

  @override
  bool get supportsPlatform => platform.isMacOS;

  @override
  bool get canListAnything => iosWorkflow.canListDevices;

  @override
  List<Device> pollingGetDevices() => IOSSimulatorUtils.instance.getAttachedDevices();
}

class IOSSimulatorUtils {
  /// Returns [IOSSimulatorUtils] active in the current app context (i.e. zone).
  static IOSSimulatorUtils get instance => context[IOSSimulatorUtils];

  List<IOSSimulator> getAttachedDevices() {
    if (!xcode.isInstalledAndMeetsVersionCheck)
      return <IOSSimulator>[];

    return SimControl.instance.getConnectedDevices().map((SimDevice device) {
      return new IOSSimulator(device.udid, name: device.name, category: device.category);
    }).toList();
  }
}

/// A wrapper around the `simctl` command line tool.
class SimControl {
  /// Returns [SimControl] active in the current app context (i.e. zone).
  static SimControl get instance => context[SimControl];

  /// Runs `simctl list --json` and returns the JSON of the corresponding
  /// [section].
  ///
  /// The return type depends on the [section] being listed but is usually
  /// either a [Map] or a [List].
  dynamic _list(SimControlListSection section) {
    // Sample output from `simctl list --json`:
    //
    // {
    //   "devicetypes": { ... },
    //   "runtimes": { ... },
    //   "devices" : {
    //     "com.apple.CoreSimulator.SimRuntime.iOS-8-2" : [
    //       {
    //         "state" : "Shutdown",
    //         "availability" : " (unavailable, runtime profile not found)",
    //         "name" : "iPhone 4s",
    //         "udid" : "1913014C-6DCB-485D-AC6B-7CD76D322F5B"
    //       },
    //       ...
    //   },
    //   "pairs": { ... },

    final List<String> command = <String>[_xcrunPath, 'simctl', 'list', '--json', section.name];
    printTrace(command.join(' '));
    final ProcessResult results = processManager.runSync(command);
    if (results.exitCode != 0) {
      printError('Error executing simctl: ${results.exitCode}\n${results.stderr}');
      return <String, Map<String, dynamic>>{};
    }

    return JSON.decode(results.stdout)[section.name];
  }

  /// Returns a list of all available devices, both potential and connected.
  List<SimDevice> getDevices() {
    final List<SimDevice> devices = <SimDevice>[];

    final Map<String, dynamic> devicesSection = _list(SimControlListSection.devices);

    for (String deviceCategory in devicesSection.keys) {
      final List<Map<String, String>> devicesData = devicesSection[deviceCategory];

      for (Map<String, String> data in devicesData) {
        devices.add(new SimDevice(deviceCategory, data));
      }
    }

    return devices;
  }

  /// Returns all the connected simulator devices.
  List<SimDevice> getConnectedDevices() {
    return getDevices().where((SimDevice device) => device.isBooted).toList();
  }

  Future<bool> isInstalled(String deviceId, String appId) {
    return exitsHappyAsync(<String>[
      _xcrunPath,
      'simctl',
      'get_app_container',
      deviceId,
      appId,
    ]);
  }

  Future<Null> install(String deviceId, String appPath) {
    return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]);
  }

  Future<Null> uninstall(String deviceId, String appId) {
    return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]);
  }

  Future<Null> launch(String deviceId, String appIdentifier, [List<String> launchArgs]) {
    final List<String> args = <String>[_xcrunPath, 'simctl', 'launch', deviceId, appIdentifier];
    if (launchArgs != null)
      args.addAll(launchArgs);
    return runCheckedAsync(args);
  }

  Future<Null> takeScreenshot(String deviceId, String outputPath) {
    return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'io', deviceId, 'screenshot', outputPath]);
  }
}

/// Enumerates all data sections of `xcrun simctl list --json` command.
class SimControlListSection {
  const SimControlListSection._(this.name);

  final String name;

  static const SimControlListSection devices = const SimControlListSection._('devices');
  static const SimControlListSection devicetypes = const SimControlListSection._('devicetypes');
  static const SimControlListSection runtimes = const SimControlListSection._('runtimes');
  static const SimControlListSection pairs = const SimControlListSection._('pairs');
}

/// A simulated device type.
///
/// Simulated device types can be listed using the command
/// `xcrun simctl list devicetypes`.
class SimDeviceType {
  SimDeviceType(this.name, this.identifier);

  /// The name of the device type.
  ///
  /// Examples:
  ///
  ///     "iPhone 6s"
  ///     "iPhone 6 Plus"
  final String name;

  /// The identifier of the device type.
  ///
  /// Examples:
  ///
  ///     "com.apple.CoreSimulator.SimDeviceType.iPhone-6s"
  ///     "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus"
  final String identifier;
}

class SimDevice {
  SimDevice(this.category, this.data);

  final String category;
  final Map<String, String> data;

  String get state => data['state'];
  String get availability => data['availability'];
  String get name => data['name'];
  String get udid => data['udid'];

  bool get isBooted => state == 'Booted';
}

class IOSSimulator extends Device {
  IOSSimulator(String id, { this.name, this.category }) : super(id);

  @override
  final String name;

  final String category;

  @override
  Future<bool> get isLocalEmulator async => true;

  @override
  bool get supportsHotMode => true;

  Map<ApplicationPackage, _IOSSimulatorLogReader> _logReaders;
  _IOSSimulatorDevicePortForwarder _portForwarder;

  String get xcrunPath => fs.path.join('/usr', 'bin', 'xcrun');

  String _getSimulatorPath() {
    return fs.path.join(homeDirPath, 'Library', 'Developer', 'CoreSimulator', 'Devices', id);
  }

  String _getSimulatorAppHomeDirectory(ApplicationPackage app) {
    final String simulatorPath = _getSimulatorPath();
    if (simulatorPath == null)
      return null;
    return fs.path.join(simulatorPath, 'data');
  }

  @override
  Future<bool> isAppInstalled(ApplicationPackage app) {
    return SimControl.instance.isInstalled(id, app.id);
  }

  @override
  Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => false;

  @override
  Future<bool> installApp(ApplicationPackage app) async {
    try {
      final IOSApp iosApp = app;
      SimControl.instance.install(id, iosApp.simulatorBundlePath);
      return true;
    } catch (e) {
      return false;
    }
  }

  @override
  Future<bool> uninstallApp(ApplicationPackage app) async {
    try {
      await SimControl.instance.uninstall(id, app.id);
      return true;
    } catch (e) {
      return false;
    }
  }

  @override
  bool isSupported() {
    if (!platform.isMacOS) {
      _supportMessage = 'iOS devices require a Mac host machine.';
      return false;
    }

    // Step 1: Check if the device is part of a blacklisted category.
    //         We do not support WatchOS or tvOS devices.

    final RegExp blacklist = new RegExp(r'Apple (TV|Watch)', caseSensitive: false);
    if (blacklist.hasMatch(name)) {
      _supportMessage = 'Flutter does not support Apple TV or Apple Watch. Select an iPhone 5s or above.';
      return false;
    }

    // Step 2: Check if the device must be rejected because of its version.
    //         There is an artificial check on older simulators where arm64
    //         targeted applications cannot be run (even though the Flutter
    //         runner on the simulator is completely different).

    // Check for unsupported iPads.
    final Match iPadMatch = new RegExp(r'iPad (2|Retina)', caseSensitive: false).firstMatch(name);
    if (iPadMatch != null) {
      _supportMessage = 'Flutter does not yet support iPad 2 or iPad Retina. Select an iPad Air or above.';
      return false;
    }

    // Check for unsupported iPhones.
    final Match iPhoneMatch = new RegExp(r'iPhone [0-5]').firstMatch(name);
    if (iPhoneMatch != null) {
      if (name == 'iPhone 5s')
        return true;
      _supportMessage = 'Flutter does not yet support iPhone 5 or earlier. Select an iPhone 5s or above.';
      return false;
    }

    return true;
  }

  String _supportMessage;

  @override
  String supportMessage() {
    if (isSupported())
      return 'Supported';

    return _supportMessage != null ? _supportMessage : 'Unknown';
  }

  @override
  Future<LaunchResult> startApp(
    ApplicationPackage app,
    BuildMode mode, {
    String mainPath,
    String route,
    DebuggingOptions debuggingOptions,
    Map<String, dynamic> platformArgs,
    String kernelPath,
    bool prebuiltApplication: false,
    bool applicationNeedsRebuild: false,
  }) async {
    if (!prebuiltApplication) {
      printTrace('Building ${app.name} for $id.');

      try {
        await _setupUpdatedApplicationBundle(app);
      } on ToolExit catch (e) {
        printError(e.message);
        return new LaunchResult.failed();
      }
    } else {
      if (!await installApp(app))
        return new LaunchResult.failed();
    }

    // Prepare launch arguments.
    final List<String> args = <String>['--enable-dart-profiling'];

    if (!prebuiltApplication) {
      args.addAll(<String>[
        '--flx=${fs.path.absolute(fs.path.join(getBuildDirectory(), 'app.flx'))}',
        '--dart-main=${fs.path.absolute(mainPath)}',
        '--packages=${fs.path.absolute('.packages')}',
      ]);
    }

    if (debuggingOptions.debuggingEnabled) {
      if (debuggingOptions.buildMode == BuildMode.debug)
        args.add('--enable-checked-mode');
      if (debuggingOptions.startPaused)
        args.add('--start-paused');
      if (debuggingOptions.useTestFonts)
        args.add('--use-test-fonts');

      final int observatoryPort = await debuggingOptions.findBestObservatoryPort();
      args.add('--observatory-port=$observatoryPort');
      final int diagnosticPort = await debuggingOptions.findBestDiagnosticPort();
      args.add('--diagnostic-port=$diagnosticPort');
    }

    ProtocolDiscovery observatoryDiscovery;
    if (debuggingOptions.debuggingEnabled)
      observatoryDiscovery = new ProtocolDiscovery.observatory(getLogReader(app: app));

    // Launch the updated application in the simulator.
    try {
      await SimControl.instance.launch(id, app.id, args);
    } catch (error) {
      printError('$error');
      return new LaunchResult.failed();
    }

    if (!debuggingOptions.debuggingEnabled) {
      return new LaunchResult.succeeded();
    }

    // Wait for the service protocol port here. This will complete once the
    // device has printed "Observatory is listening on..."
    printTrace('Waiting for observatory port to be available...');

    try {
      final Uri deviceUri = await observatoryDiscovery.uri;
      return new LaunchResult.succeeded(observatoryUri: deviceUri);
    } catch (error) {
      printError('Error waiting for a debug connection: $error');
      return new LaunchResult.failed();
    } finally {
      observatoryDiscovery.cancel();
    }
  }

  Future<bool> _applicationIsInstalledAndRunning(ApplicationPackage app) async {
    final List<bool> criteria = await Future.wait(<Future<bool>>[
      isAppInstalled(app),
      exitsHappyAsync(<String>['/usr/bin/killall', 'Runner']),
    ]);
    return criteria.reduce((bool a, bool b) => a && b);
  }

  Future<Null> _setupUpdatedApplicationBundle(ApplicationPackage app) async {
    await _sideloadUpdatedAssetsForInstalledApplicationBundle(app);

    if (!await _applicationIsInstalledAndRunning(app))
      return _buildAndInstallApplicationBundle(app);
  }

  Future<Null> _buildAndInstallApplicationBundle(ApplicationPackage app) async {
    // Step 1: Build the Xcode project.
    // The build mode for the simulator is always debug.
    final XcodeBuildResult buildResult = await buildXcodeProject(app: app, mode: BuildMode.debug, buildForDevice: false);
    if (!buildResult.success)
      throwToolExit('Could not build the application for the simulator.');

    // Step 2: Assert that the Xcode project was successfully built.
    final IOSApp iosApp = app;
    final Directory bundle = fs.directory(iosApp.simulatorBundlePath);
    final bool bundleExists = bundle.existsSync();
    if (!bundleExists)
      throwToolExit('Could not find the built application bundle at ${bundle.path}.');

    // Step 3: Install the updated bundle to the simulator.
    await SimControl.instance.install(id, fs.path.absolute(bundle.path));
  }

  Future<Null> _sideloadUpdatedAssetsForInstalledApplicationBundle(ApplicationPackage app) =>
      flx.build(precompiledSnapshot: true);

  @override
  Future<bool> stopApp(ApplicationPackage app) async {
    // Currently we don't have a way to stop an app running on iOS.
    return false;
  }

  Future<bool> pushFile(
      ApplicationPackage app, String localFile, String targetFile) async {
    if (platform.isMacOS) {
      final String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app);
      await runCheckedAsync(<String>['cp', localFile, fs.path.join(simulatorHomeDirectory, targetFile)]);
      return true;
    }
    return false;
  }

  String get logFilePath {
    return fs.path.join(homeDirPath, 'Library', 'Logs', 'CoreSimulator', id, 'system.log');
  }

  @override
  Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;

  @override
  Future<String> get sdkNameAndVersion async => category;

  @override
  DeviceLogReader getLogReader({ApplicationPackage app}) {
    _logReaders ??= <ApplicationPackage, _IOSSimulatorLogReader>{};
    return _logReaders.putIfAbsent(app, () => new _IOSSimulatorLogReader(this, app));
  }

  @override
  DevicePortForwarder get portForwarder => _portForwarder ??= new _IOSSimulatorDevicePortForwarder(this);

  @override
  void clearLogs() {
    final File logFile = fs.file(logFilePath);
    if (logFile.existsSync()) {
      final RandomAccessFile randomFile = logFile.openSync(mode: FileMode.WRITE);
      randomFile.truncateSync(0);
      randomFile.closeSync();
    }
  }

  void ensureLogsExists() {
    final File logFile = fs.file(logFilePath);
    if (!logFile.existsSync())
      logFile.writeAsBytesSync(<int>[]);
  }

  bool get _xcodeVersionSupportsScreenshot {
    return xcode.xcodeMajorVersion > 8 || (xcode.xcodeMajorVersion == 8 && xcode.xcodeMinorVersion >= 2);
  }

  @override
  bool get supportsScreenshot => _xcodeVersionSupportsScreenshot;

  @override
  Future<Null> takeScreenshot(File outputFile) {
    return SimControl.instance.takeScreenshot(id, outputFile.path);
  }
}

class _IOSSimulatorLogReader extends DeviceLogReader {
  String _appName;

  _IOSSimulatorLogReader(this.device, ApplicationPackage app) {
    _linesController = new StreamController<String>.broadcast(
      onListen: _start,
      onCancel: _stop
    );
    _appName = app == null ? null : app.name.replaceAll('.app', '');
  }

  final IOSSimulator device;

  StreamController<String> _linesController;

  // We log from two files: the device and the system log.
  Process _deviceProcess;
  Process _systemProcess;

  @override
  Stream<String> get logLines => _linesController.stream;

  @override
  String get name => device.name;

  Future<Null> _start() async {
    // Device log.
    device.ensureLogsExists();
    _deviceProcess = await runCommand(<String>['tail', '-n', '0', '-F', device.logFilePath]);
    _deviceProcess.stdout.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onDeviceLine);
    _deviceProcess.stderr.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onDeviceLine);

    // Track system.log crashes.
    // ReportCrash[37965]: Saved crash report for FlutterRunner[37941]...
    _systemProcess = await runCommand(<String>['tail', '-n', '0', '-F', '/private/var/log/system.log']);
    _systemProcess.stdout.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onSystemLine);
    _systemProcess.stderr.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onSystemLine);

    _deviceProcess.exitCode.whenComplete(() {
      if (_linesController.hasListener)
        _linesController.close();
    });
  }

  // Match the log prefix (in order to shorten it):
  //   'Jan 29 01:31:44 devoncarew-macbookpro3 SpringBoard[96648]: ...'
  static final RegExp _mapRegex = new RegExp(r'\S+ +\S+ +\S+ \S+ (.+)\[\d+\]\)?: (.*)$');

  // Jan 31 19:23:28 --- last message repeated 1 time ---
  static final RegExp _lastMessageSingleRegex = new RegExp(r'\S+ +\S+ +\S+ --- last message repeated 1 time ---$');
  static final RegExp _lastMessageMultipleRegex = new RegExp(r'\S+ +\S+ +\S+ --- last message repeated (\d+) times ---$');

  static final RegExp _flutterRunnerRegex = new RegExp(r' FlutterRunner\[\d+\] ');

  /// List of log categories to always show in the logs, even if this is an app-specific
  /// [DeviceLogReader]. Add to this list to make the log output more verbose.
  static final List<String> _whitelistedLogCategories = <String>[
    'CoreSimulatorBridge',
  ];

  String _filterDeviceLine(String string) {
    final Match match = _mapRegex.matchAsPrefix(string);
    if (match != null) {
      final String category = match.group(1);
      final String content = match.group(2);

      // Filter out some messages that clearly aren't related to Flutter.
      if (string.contains(': could not find icon for representation -> com.apple.'))
        return null;

      if (category == 'CoreSimulatorBridge'
          && content.startsWith('Pasteboard change listener callback port'))
        return null;

      if (category == 'routined'
          && content.startsWith('CoreLocation: Error occurred while trying to retrieve motion state update'))
        return null;

      if (category == 'syslogd' && content == 'ASL Sender Statistics')
        return null;

      // assertiond: assertion failed: 15E65 13E230: assertiond + 15801 [3C808658-78EC-3950-A264-79A64E0E463B]: 0x1
      if (category == 'assertiond'
          && content.startsWith('assertion failed: ')
          && content.endsWith(']: 0x1'))
         return null;

      // assertion failed: 15G1212 13E230: libxpc.dylib + 57882 [66C28065-C9DB-3C8E-926F-5A40210A6D1B]: 0x7d
      if (category == 'Runner'
          && content.startsWith('assertion failed: ')
          && content.contains(' libxpc.dylib '))
        return null;

      if (_appName == null || _whitelistedLogCategories.contains(category))
        return '$category: $content';
      else if (category == _appName)
        return content;

      return null;
    }

    if (_lastMessageSingleRegex.matchAsPrefix(string) != null)
      return null;

    if (new RegExp(r'assertion failed: .* libxpc.dylib .* 0x7d$').matchAsPrefix(string) != null)
      return null;

    return string;
  }

  String _lastLine;

  void _onDeviceLine(String line) {
    printTrace('[DEVICE LOG] $line');
    final Match multi = _lastMessageMultipleRegex.matchAsPrefix(line);

    if (multi != null) {
      if (_lastLine != null) {
        int repeat = int.parse(multi.group(1));
        repeat = math.max(0, math.min(100, repeat));
        for (int i = 1; i < repeat; i++)
          _linesController.add(_lastLine);
      }
    } else {
      _lastLine = _filterDeviceLine(line);
      if (_lastLine != null)
        _linesController.add(_lastLine);
    }
  }

  String _filterSystemLog(String string) {
    final Match match = _mapRegex.matchAsPrefix(string);
    return match == null ? string : '${match.group(1)}: ${match.group(2)}';
  }

  void _onSystemLine(String line) {
    printTrace('[SYS LOG] $line');
    if (!_flutterRunnerRegex.hasMatch(line))
      return;

    final String filteredLine = _filterSystemLog(line);
    if (filteredLine == null)
      return;

    _linesController.add(filteredLine);
  }

  void _stop() {
    _deviceProcess?.kill();
    _systemProcess?.kill();
  }
}

int compareIosVersions(String v1, String v2) {
  final List<int> v1Fragments = v1.split('.').map(int.parse).toList();
  final List<int> v2Fragments = v2.split('.').map(int.parse).toList();

  int i = 0;
  while(i < v1Fragments.length && i < v2Fragments.length) {
    final int v1Fragment = v1Fragments[i];
    final int v2Fragment = v2Fragments[i];
    if (v1Fragment != v2Fragment)
      return v1Fragment.compareTo(v2Fragment);
    i++;
  }
  return v1Fragments.length.compareTo(v2Fragments.length);
}

/// Matches on device type given an identifier.
///
/// Example device type identifiers:
///   ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-5
///   ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-6
///   ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus
///   ✗ com.apple.CoreSimulator.SimDeviceType.iPad-2
///   ✗ com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm
final RegExp _iosDeviceTypePattern =
    new RegExp(r'com.apple.CoreSimulator.SimDeviceType.iPhone-(\d+)(.*)');

int compareIphoneVersions(String id1, String id2) {
  final Match m1 = _iosDeviceTypePattern.firstMatch(id1);
  final Match m2 = _iosDeviceTypePattern.firstMatch(id2);

  final int v1 = int.parse(m1[1]);
  final int v2 = int.parse(m2[1]);

  if (v1 != v2)
    return v1.compareTo(v2);

  // Sorted in the least preferred first order.
  const List<String> qualifiers = const <String>['-Plus', '', 's-Plus', 's'];

  final int q1 = qualifiers.indexOf(m1[2]);
  final int q2 = qualifiers.indexOf(m2[2]);
  return q1.compareTo(q2);
}

class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {
  _IOSSimulatorDevicePortForwarder(this.device);

  final IOSSimulator device;

  final List<ForwardedPort> _ports = <ForwardedPort>[];

  @override
  List<ForwardedPort> get forwardedPorts {
    return _ports;
  }

  @override
  Future<int> forward(int devicePort, {int hostPort: null}) async {
    if ((hostPort == null) || (hostPort == 0)) {
      hostPort = devicePort;
    }
    assert(devicePort == hostPort);
    _ports.add(new ForwardedPort(devicePort, hostPort));
    return hostPort;
  }

  @override
  Future<Null> unforward(ForwardedPort forwardedPort) async {
    _ports.remove(forwardedPort);
  }
}
