// 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 '../../base/utils.dart';
import '../../globals.dart' as globals;

/// The caching strategy for the generated service worker.
enum ServiceWorkerStrategy implements CliEnum {
  /// Download the app shell eagerly and all other assets lazily.
  /// Prefer the offline cached version.
  offlineFirst,

  /// Do not generate a service worker,
  none;

  @override
  String get cliName => snakeCase(name, '-');

  static ServiceWorkerStrategy fromCliName(String? value) => value == null
      ? ServiceWorkerStrategy.offlineFirst
      : values.singleWhere(
          (ServiceWorkerStrategy element) => element.cliName == value,
          orElse: () =>
              throw ArgumentError.value(value, 'value', 'Not supported.'),
        );

  @override
  String get helpText => switch (this) {
        ServiceWorkerStrategy.offlineFirst =>
          'Attempt to cache the application shell eagerly and then lazily '
              'cache all subsequent assets as they are loaded. When making a '
              'network request for an asset, the offline cache will be '
              'preferred.',
        ServiceWorkerStrategy.none =>
          'Generate a service worker with no body. This is useful for local '
              'testing or in cases where the service worker caching '
              'functionality is not desirable'
      };
}

/// Generate a service worker with an app-specific cache name a map of
/// resource files.
///
/// The tool embeds file hashes directly into the worker so that the byte for byte
/// invalidation will automatically reactivate workers whenever a new
/// version is deployed.
String generateServiceWorker(
  String fileGeneratorsPath,
  Map<String, String> resources,
  List<String> coreBundle, {
  required ServiceWorkerStrategy serviceWorkerStrategy,
}) {
  if (serviceWorkerStrategy == ServiceWorkerStrategy.none) {
    return '';
  }

  final String flutterServiceWorkerJsPath = globals.localFileSystem.path.join(
    fileGeneratorsPath,
    'js',
    'flutter_service_worker.js',
  );
  return globals.localFileSystem
      .file(flutterServiceWorkerJsPath)
      .readAsStringSync()
      .replaceAll(
        r'$$RESOURCES_MAP',
        '{${resources.entries.map((MapEntry<String, String> entry) => '"${entry.key}": "${entry.value}"').join(",\n")}}',
      )
      .replaceAll(
        r'$$CORE_LIST',
        '[${coreBundle.map((String file) => '"$file"').join(',\n')}]',
      );
}
