// 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';

// ignore: import_of_legacy_library_into_null_safe
import 'package:dwds/dwds.dart';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vmservice;
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
    hide StackTrace;

import '../application_package.dart';
import '../base/async_guard.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/net.dart';
import '../base/terminal.dart';
import '../base/time.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../build_system/targets/web.dart';
import '../cache.dart';
import '../dart/language_version.dart';
import '../devfs.dart';
import '../device.dart';
import '../flutter_plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../resident_devtools_handler.dart';
import '../resident_runner.dart';
import '../run_hot.dart';
import '../vmservice.dart';
import '../web/chrome.dart';
import '../web/compile.dart';
import '../web/file_generators/main_dart.dart' as main_dart;
import '../web/web_device.dart';
import '../web/web_runner.dart';
import 'devfs_web.dart';

/// Injectable factory to create a [ResidentWebRunner].
class DwdsWebRunnerFactory extends WebRunnerFactory {
  @override
  ResidentRunner createWebRunner(
    FlutterDevice device, {
    String? target,
    required bool stayResident,
    required FlutterProject flutterProject,
    required bool? ipv6,
    required DebuggingOptions debuggingOptions,
    UrlTunneller? urlTunneller,
    required Logger logger,
    required FileSystem fileSystem,
    required SystemClock systemClock,
    required Usage usage,
    bool machine = false,
  }) {
    return ResidentWebRunner(
      device,
      target: target,
      flutterProject: flutterProject,
      debuggingOptions: debuggingOptions,
      ipv6: ipv6,
      stayResident: stayResident,
      urlTunneller: urlTunneller,
      machine: machine,
      usage: usage,
      systemClock: systemClock,
      fileSystem: fileSystem,
      logger: logger,
    );
  }
}

const String kExitMessage = 'Failed to establish connection with the application '
  'instance in Chrome.\nThis can happen if the websocket connection used by the '
  'web tooling is unable to correctly establish a connection, for example due to a firewall.';

class ResidentWebRunner extends ResidentRunner {
  ResidentWebRunner(
    FlutterDevice device, {
    String? target,
    bool stayResident = true,
    bool machine = false,
    required this.flutterProject,
    required bool? ipv6,
    required DebuggingOptions debuggingOptions,
    required FileSystem fileSystem,
    required Logger logger,
    required SystemClock systemClock,
    required Usage usage,
    UrlTunneller? urlTunneller,
    ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler,
  }) : _fileSystem = fileSystem,
       _logger = logger,
       _systemClock = systemClock,
       _usage = usage,
       _urlTunneller = urlTunneller,
       super(
          <FlutterDevice>[device],
          target: target ?? fileSystem.path.join('lib', 'main.dart'),
          debuggingOptions: debuggingOptions,
          ipv6: ipv6,
          stayResident: stayResident,
          machine: machine,
          devtoolsHandler: devtoolsHandler,
        );

  final FileSystem _fileSystem;
  final Logger _logger;
  final SystemClock _systemClock;
  final Usage _usage;
  final UrlTunneller? _urlTunneller;

  @override
  Logger get logger => _logger;

  @override
  FileSystem get fileSystem => _fileSystem;

  FlutterDevice? get device => flutterDevices.first;
  final FlutterProject flutterProject;
  DateTime? firstBuildTime;

  // Used with the new compiler to generate a bootstrap file containing plugins
  // and platform initialization.
  Directory? _generatedEntrypointDirectory;

  // Only the debug builds of the web support the service protocol.
  @override
  bool get supportsServiceProtocol => isRunningDebug && deviceIsDebuggable;

  @override
  bool get debuggingEnabled => isRunningDebug && deviceIsDebuggable;

  /// WebServer device is debuggable when running with --start-paused.
  bool get deviceIsDebuggable => device!.device is! WebServerDevice || debuggingOptions.startPaused;

  @override
  bool get supportsWriteSkSL => false;

  @override
  // Web uses a different plugin registry.
  bool get generateDartPluginRegistry => false;

  bool get _enableDwds => debuggingEnabled;

  ConnectionResult? _connectionResult;
  StreamSubscription<vmservice.Event>? _stdOutSub;
  StreamSubscription<vmservice.Event>? _stdErrSub;
  StreamSubscription<vmservice.Event>? _extensionEventSub;
  bool _exited = false;
  WipConnection? _wipConnection;
  ChromiumLauncher? _chromiumLauncher;

  FlutterVmService get _vmService {
    if (_instance != null) {
      return _instance!;
    }
    final vmservice.VmService? service =_connectionResult?.vmService;
    final Uri websocketUri = Uri.parse(_connectionResult!.debugConnection!.uri);
    final Uri httpUri = _httpUriFromWebsocketUri(websocketUri);
    return _instance ??= FlutterVmService(service!, wsAddress: websocketUri, httpAddress: httpUri);
  }
  FlutterVmService? _instance;

  @override
  Future<void> cleanupAfterSignal() async {
    await _cleanup();
  }

  @override
  Future<void> cleanupAtFinish() async {
    await _cleanup();
  }

  Future<void> _cleanup() async {
    if (_exited) {
      return;
    }
    await residentDevtoolsHandler!.shutdown();
    await _stdOutSub?.cancel();
    await _stdErrSub?.cancel();
    await _extensionEventSub?.cancel();
    await device!.device!.stopApp(null);
    try {
      _generatedEntrypointDirectory?.deleteSync(recursive: true);
    } on FileSystemException {
      // Best effort to clean up temp dirs.
      _logger.printTrace(
        'Failed to clean up temp directory: ${_generatedEntrypointDirectory!.path}',
      );
    }
    _exited = true;
  }

  Future<void> _cleanupAndExit() async {
    await _cleanup();
    appFinished();
  }

  @override
  void printHelp({bool details = true}) {
    if (details) {
      return printHelpDetails();
    }
    const String fire = '🔥';
    const String rawMessage =
        '  To hot restart changes while running, press "r" or "R".';
    final String message = _logger.terminal.color(
      fire + _logger.terminal.bolden(rawMessage),
      TerminalColor.red,
    );
    _logger.printStatus(message);
    const String quitMessage = 'To quit, press "q".';
    _logger.printStatus('For a more detailed help message, press "h". $quitMessage');
    _logger.printStatus('');
    printDebuggerList();
  }

  @override
  Future<void> stopEchoingDeviceLog() async {
    // Do nothing for ResidentWebRunner
    await device!.stopEchoingDeviceLog();
  }

  @override
  Future<int> run({
    Completer<DebugConnectionInfo>? connectionInfoCompleter,
    Completer<void>? appStartedCompleter,
    bool enableDevTools = false, // ignored, we don't yet support devtools for web
    String? route,
  }) async {
    firstBuildTime = DateTime.now();
    final ApplicationPackage? package = await ApplicationPackageFactory.instance!.getPackageForPlatform(
      TargetPlatform.web_javascript,
      buildInfo: debuggingOptions.buildInfo,
    );
    if (package == null) {
      _logger.printStatus('This application is not configured to build on the web.');
      _logger.printStatus('To add web support to a project, run `flutter create .`.');
    }
    final String modeName = debuggingOptions.buildInfo.friendlyModeName;
    _logger.printStatus(
      'Launching ${getDisplayPath(target, _fileSystem)} '
      'on ${device!.device!.name} in $modeName mode...',
    );
    if (device!.device is ChromiumDevice) {
      _chromiumLauncher = (device!.device! as ChromiumDevice).chromeLauncher;
    }

    try {
      return await asyncGuard(() async {
        final ExpressionCompiler? expressionCompiler =
          debuggingOptions.webEnableExpressionEvaluation
              ? WebExpressionCompiler(device!.generator!, fileSystem: _fileSystem)
              : null;
        device!.devFS = WebDevFS(
          hostname: debuggingOptions.hostname ?? 'localhost',
          port: debuggingOptions.port != null
            ? int.tryParse(debuggingOptions.port!)
            : null,
          packagesFilePath: packagesFilePath,
          urlTunneller: _urlTunneller,
          useSseForDebugProxy: debuggingOptions.webUseSseForDebugProxy,
          useSseForDebugBackend: debuggingOptions.webUseSseForDebugBackend,
          useSseForInjectedClient: debuggingOptions.webUseSseForInjectedClient,
          buildInfo: debuggingOptions.buildInfo,
          enableDwds: _enableDwds,
          enableDds: debuggingOptions.enableDds,
          entrypoint: _fileSystem.file(target).uri,
          expressionCompiler: expressionCompiler,
          chromiumLauncher: _chromiumLauncher,
          nullAssertions: debuggingOptions.nullAssertions,
          nullSafetyMode: debuggingOptions.buildInfo.nullSafetyMode,
          nativeNullAssertions: debuggingOptions.nativeNullAssertions,
        );
        final Uri url = await device!.devFS!.create();
        if (debuggingOptions.buildInfo.isDebug) {
          await runSourceGenerators();
          final UpdateFSReport report = await _updateDevFS(fullRestart: true);
          if (!report.success) {
            _logger.printError('Failed to compile application.');
            appFailedToStart();
            return 1;
          }
          device!.generator!.accept();
          cacheInitialDillCompilation();
        } else {
          await buildWeb(
            flutterProject,
            target,
            debuggingOptions.buildInfo,
            false,
            kNoneWorker,
            true,
            debuggingOptions.nativeNullAssertions,
            false,
          );
        }
        await device!.device!.startApp(
          package,
          mainPath: target,
          debuggingOptions: debuggingOptions,
          platformArgs: <String, Object>{
            'uri': url.toString(),
          },
        );
        return attach(
          connectionInfoCompleter: connectionInfoCompleter,
          appStartedCompleter: appStartedCompleter,
          enableDevTools: enableDevTools,
        );
      });
    } on WebSocketException catch (error, stackTrace) {
      appFailedToStart();
      _logger.printError('$error', stackTrace: stackTrace);
      throwToolExit(kExitMessage);
    } on ChromeDebugException catch (error, stackTrace) {
      appFailedToStart();
      _logger.printError('$error', stackTrace: stackTrace);
      throwToolExit(kExitMessage);
    } on AppConnectionException catch (error, stackTrace) {
      appFailedToStart();
      _logger.printError('$error', stackTrace: stackTrace);
      throwToolExit(kExitMessage);
    } on SocketException catch (error, stackTrace) {
      appFailedToStart();
      _logger.printError('$error', stackTrace: stackTrace);
      throwToolExit(kExitMessage);
    } on Exception {
      appFailedToStart();
      rethrow;
    }
  }

  @override
  Future<OperationResult> restart({
    bool fullRestart = false,
    bool? pause = false,
    String? reason,
    bool benchmarkMode = false,
  }) async {
    final DateTime start = _systemClock.now();
    final Status status = _logger.startProgress(
      'Performing hot restart...',
      progressId: 'hot.restart',
    );

    if (debuggingOptions.buildInfo.isDebug) {
      await runSourceGenerators();
      // Full restart is always false for web, since the extra recompile is wasteful.
      final UpdateFSReport report = await _updateDevFS();
      if (report.success) {
        device!.generator!.accept();
      } else {
        status.stop();
        await device!.generator!.reject();
        return OperationResult(1, 'Failed to recompile application.');
      }
    } else {
      try {
        await buildWeb(
          flutterProject,
          target,
          debuggingOptions.buildInfo,
          false,
          kNoneWorker,
          true,
          debuggingOptions.nativeNullAssertions,
          false,
          baseHref: kBaseHref,
        );
      } on ToolExit {
        return OperationResult(1, 'Failed to recompile application.');
      }
    }

    try {
      if (!deviceIsDebuggable) {
        _logger.printStatus('Recompile complete. Page requires refresh.');
      } else if (isRunningDebug) {
        await _vmService.service.callMethod('hotRestart');
      } else {
        // On non-debug builds, a hard refresh is required to ensure the
        // up to date sources are loaded.
        await _wipConnection?.sendCommand('Page.reload', <String, Object>{
          'ignoreCache': !debuggingOptions.buildInfo.isDebug,
        });
      }
    } on Exception catch (err) {
      return OperationResult(1, err.toString(), fatal: true);
    } finally {
      status.stop();
    }

    final Duration elapsed = _systemClock.now().difference(start);
    final String elapsedMS = getElapsedAsMilliseconds(elapsed);
    _logger.printStatus('Restarted application in $elapsedMS.');
    unawaited(residentDevtoolsHandler!.hotRestart(flutterDevices));

    // Don't track restart times for dart2js builds or web-server devices.
    if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) {
      _usage.sendTiming('hot', 'web-incremental-restart', elapsed);
      HotEvent(
        'restart',
        targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript),
        sdkName: await device!.device!.sdkNameAndVersion,
        emulator: false,
        fullRestart: true,
        reason: reason,
        overallTimeInMs: elapsed.inMilliseconds,
        fastReassemble: false,
      ).send();
    }
    return OperationResult.ok;
  }

  // Flutter web projects need to include a generated main entrypoint to call the
  // appropriate bootstrap method and inject plugins.
  // Keep this in sync with build_system/targets/web.dart.
  Future<Uri> _generateEntrypoint(Uri mainUri, PackageConfig? packageConfig) async {
    File? result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart');
    if (_generatedEntrypointDirectory == null) {
      _generatedEntrypointDirectory ??= _fileSystem.systemTempDirectory.createTempSync('flutter_tools.')
        ..createSync();
      result = _generatedEntrypointDirectory!.childFile('web_entrypoint.dart');

      // Generates the generated_plugin_registrar
      await injectBuildTimePluginFiles(flutterProject, webPlatform: true, destination: _generatedEntrypointDirectory!);
      // The below works because `injectBuildTimePluginFiles` is configured to write
      // the web_plugin_registrant.dart file alongside the generated main.dart
      const String generatedImport = 'web_plugin_registrant.dart';

      Uri? importedEntrypoint = packageConfig!.toPackageUri(mainUri);
      // Special handling for entrypoints that are not under lib, such as test scripts.
      if (importedEntrypoint == null) {
        final String parent = _fileSystem.file(mainUri).parent.path;
        flutterDevices.first.generator!
          ..addFileSystemRoot(parent)
          ..addFileSystemRoot(_fileSystem.directory('test').absolute.path);
        importedEntrypoint = Uri(
          scheme: 'org-dartlang-app',
          path: '/${mainUri.pathSegments.last}',
        );
      }
      final LanguageVersion languageVersion = determineLanguageVersion(
        _fileSystem.file(mainUri),
        packageConfig[flutterProject.manifest.appName],
        Cache.flutterRoot!,
      );

      final String entrypoint = main_dart.generateMainDartFile(importedEntrypoint.toString(),
        languageVersion: languageVersion,
        pluginRegistrantEntrypoint: generatedImport,
      );

      result.writeAsStringSync(entrypoint);
    }
    return result!.absolute.uri;
  }

  Future<UpdateFSReport> _updateDevFS({bool fullRestart = false}) async {
    final bool isFirstUpload = !assetBundle.wasBuiltOnce();
    final bool rebuildBundle = assetBundle.needsBuild();
    if (rebuildBundle) {
      _logger.printTrace('Updating assets');
      final int result = await assetBundle.build(
        packagesPath: debuggingOptions.buildInfo.packagesPath,
        targetPlatform: TargetPlatform.web_javascript,
      );
      if (result != 0) {
        return UpdateFSReport();
      }
    }
    final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
      lastCompiled: device!.devFS!.lastCompiled,
      urisToMonitor: device!.devFS!.sources,
      packagesPath: packagesFilePath,
      packageConfig: device!.devFS!.lastPackageConfig
        ?? debuggingOptions.buildInfo.packageConfig,
    );
    final Status devFSStatus = _logger.startProgress(
      'Waiting for connection from debug service on ${device!.device!.name}...',
    );
    final UpdateFSReport report = await device!.devFS!.update(
      mainUri: await _generateEntrypoint(
        _fileSystem.file(mainPath).absolute.uri,
        invalidationResult.packageConfig,
      ),
      target: target,
      bundle: assetBundle,
      firstBuildTime: firstBuildTime,
      bundleFirstUpload: isFirstUpload,
      generator: device!.generator!,
      fullRestart: fullRestart,
      dillOutputPath: dillOutputPath,
      projectRootPath: projectRootPath,
      pathToReload: getReloadPath(fullRestart: fullRestart, swap: false),
      invalidatedFiles: invalidationResult.uris!,
      packageConfig: invalidationResult.packageConfig!,
      trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation,
      shaderCompiler: device!.developmentShaderCompiler,
    );
    devFSStatus.stop();
    _logger.printTrace('Synced ${getSizeAsMB(report.syncedBytes)}.');
    return report;
  }

  @override
  Future<int> attach({
    Completer<DebugConnectionInfo>? connectionInfoCompleter,
    Completer<void>? appStartedCompleter,
    bool allowExistingDdsInstance = false,
    bool enableDevTools = false, // ignored, we don't yet support devtools for web
    bool needsFullRestart = true,
  }) async {
    if (_chromiumLauncher != null) {
      final Chromium chrome = await _chromiumLauncher!.connectedInstance;
      final ChromeTab? chromeTab = await chrome.chromeConnection.getTab((ChromeTab chromeTab) {
        return !chromeTab.url.startsWith('chrome-extension');
      }, retryFor: const Duration(seconds: 5));
      if (chromeTab == null) {
        throwToolExit('Failed to connect to Chrome instance.');
      }
      _wipConnection = await chromeTab.connect();
    }
    Uri? websocketUri;
    if (supportsServiceProtocol) {
      final WebDevFS webDevFS = device!.devFS! as WebDevFS;
      final bool useDebugExtension = device!.device is WebServerDevice && debuggingOptions.startPaused;
      _connectionResult = await webDevFS.connect(useDebugExtension);
      unawaited(_connectionResult!.debugConnection!.onDone.whenComplete(_cleanupAndExit));

      void onLogEvent(vmservice.Event event)  {
        final String message = processVmServiceMessage(event);
        _logger.printStatus(message);
      }

      _stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent);
      _stdErrSub = _vmService.service.onStderrEvent.listen(onLogEvent);
      try {
        await _vmService.service.streamListen(vmservice.EventStreams.kStdout);
      } on vmservice.RPCError {
        // It is safe to ignore this error because we expect an error to be
        // thrown if we're not already subscribed.
      }
      try {
        await _vmService.service.streamListen(vmservice.EventStreams.kStderr);
      } on vmservice.RPCError {
        // It is safe to ignore this error because we expect an error to be
        // thrown if we're not already subscribed.
      }
      try {
        await _vmService.service.streamListen(vmservice.EventStreams.kIsolate);
      } on vmservice.RPCError {
        // It is safe to ignore this error because we expect an error to be
        // thrown if we're not already subscribed.
      }
      await setUpVmService(
        (String isolateId, {
          bool? force,
          bool? pause,
        }) async {
          await restart(pause: pause);
        },
        null,
        null,
        device!.device,
        null,
        printStructuredErrorLog,
        _vmService.service,
      );


      websocketUri = Uri.parse(_connectionResult!.debugConnection!.uri);
      device!.vmService = _vmService;

      // Run main immediately if the app is not started paused or if there
      // is no debugger attached. Otherwise, runMain when a resume event
      // is received.
      if (!debuggingOptions.startPaused || !supportsServiceProtocol) {
        _connectionResult!.appConnection!.runMain();
      } else {
        late StreamSubscription<void> resumeSub;
        resumeSub = _vmService.service.onDebugEvent
            .listen((vmservice.Event event) {
          if (event.type == vmservice.EventKind.kResume) {
            _connectionResult!.appConnection!.runMain();
            resumeSub.cancel();
          }
        });
      }
      if (enableDevTools) {
        // The method below is guaranteed never to return a failing future.
        unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
          devToolsServerAddress: debuggingOptions.devToolsServerAddress,
          flutterDevices: flutterDevices,
        ));
      }
    }
    if (websocketUri != null) {
      if (debuggingOptions.vmserviceOutFile != null) {
        _fileSystem.file(debuggingOptions.vmserviceOutFile)
          ..createSync(recursive: true)
          ..writeAsStringSync(websocketUri.toString());
      }
      _logger.printStatus('Debug service listening on $websocketUri');
      _logger.printStatus('');
      if (debuggingOptions.buildInfo.nullSafetyMode ==  NullSafetyMode.sound) {
        _logger.printStatus('💪 Running with sound null safety 💪', emphasis: true);
      } else {
        _logger.printStatus(
          'Running without sound null safety ⚠️',
          emphasis: true,
        );
        _logger.printStatus(
          'Dart 3 will only support sound null safety, see https://dart.dev/null-safety',
        );
      }
    }
    appStartedCompleter?.complete();
    connectionInfoCompleter?.complete(DebugConnectionInfo(wsUri: websocketUri));
    if (stayResident) {
      await waitForAppToFinish();
    } else {
      await stopEchoingDeviceLog();
      await exitApp();
    }
    await cleanupAtFinish();
    return 0;
  }

  @override
  Future<void> exitApp() async {
    await device!.exitApps();
    appFinished();
  }
}

Uri _httpUriFromWebsocketUri(Uri websocketUri) {
  const String wsPath = '/ws';
  final String path = websocketUri.path;
  return websocketUri.replace(scheme: 'http', path: path.substring(0, path.length - wsPath.length));
}
