// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. 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:convert';
import 'dart:io';

import 'package:dwds/src/debugging/metadata/provider.dart';
import 'package:dwds/src/loaders/require.dart';
import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/readers/asset_reader.dart';
import 'package:dwds/src/services/expression_compiler.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:shelf/shelf.dart';

/// Provides a [RequireStrategy] suitable for use with `package:build_runner`.
class BuildRunnerRequireStrategyProvider {
  final _logger = Logger('BuildRunnerRequireStrategyProvider');

  final Handler _assetHandler;
  final ReloadConfiguration _configuration;
  final AssetReader _assetReader;
  final BuildSettings _buildSettings;

  late final RequireStrategy _requireStrategy = RequireStrategy(
    _configuration,
    _moduleProvider,
    _digestsProvider,
    _moduleForServerPath,
    _serverPathForModule,
    _sourceMapPathForModule,
    _serverPathForAppUri,
    _moduleInfoForProvider,
    _assetReader,
    _buildSettings,
  );

  BuildRunnerRequireStrategyProvider(
    this._assetHandler,
    this._configuration,
    this._assetReader,
    this._buildSettings,
  );

  RequireStrategy get strategy => _requireStrategy;

  Future<Map<String, String>> _digestsProvider(
    MetadataProvider metadataProvider,
  ) async {
    final modules = await metadataProvider.modulePathToModule;

    final digestsPath = metadataProvider.entrypoint
        .replaceAll('.dart.bootstrap.js', '.digests');
    final response = await _assetHandler(
      Request('GET', Uri.parse('http://foo:0000/$digestsPath')),
    );
    if (response.statusCode != HttpStatus.ok) {
      throw StateError('Could not read digests at path: $digestsPath');
    }
    final body = await response.readAsString();
    final digests = json.decode(body) as Map<String, dynamic>;

    for (final key in digests.keys) {
      if (!modules.containsKey(key)) {
        _logger.warning('Digest key $key is not a module name.');
      }
    }

    return {
      for (var entry in digests.entries)
        if (modules.containsKey(entry.key))
          modules[entry.key]!: entry.value as String,
    };
  }

  Future<Map<String, String>> _moduleProvider(
    MetadataProvider metadataProvider,
  ) async =>
      (await metadataProvider.moduleToModulePath).map(
        (key, value) =>
            MapEntry(key, stripTopLevelDirectory(removeJsExtension(value))),
      );

  Future<String?> _moduleForServerPath(
    MetadataProvider metadataProvider,
    String serverPath,
  ) async {
    final modulePathToModule = await metadataProvider.modulePathToModule;
    final relativePath = stripLeadingSlashes(serverPath);
    for (var e in modulePathToModule.entries) {
      if (stripTopLevelDirectory(e.key) == relativePath) {
        return e.value;
      }
    }
    return null;
  }

  Future<String?> _serverPathForModule(
    MetadataProvider metadataProvider,
    String module,
  ) async {
    final modulePath = (await metadataProvider.moduleToModulePath)[module];
    return modulePath == null ? null : stripTopLevelDirectory(modulePath);
  }

  Future<String?> _sourceMapPathForModule(
    MetadataProvider metadataProvider,
    String module,
  ) async {
    final sourceMapPath = (await metadataProvider.moduleToSourceMap)[module];
    return sourceMapPath == null ? null : stripTopLevelDirectory(sourceMapPath);
  }

  String? _serverPathForAppUri(String appUrl) {
    final appUri = Uri.parse(appUrl);
    if (appUri.isScheme('org-dartlang-app')) {
      // We skip the root from which we are serving.
      return appUri.pathSegments.skip(1).join('/');
    }
    if (appUri.isScheme('package')) {
      return '/packages/${appUri.path}';
    }
    return null;
  }

  Future<Map<String, ModuleInfo>> _moduleInfoForProvider(
    MetadataProvider metadataProvider,
  ) async {
    final modules = await metadataProvider.modules;
    final result = <String, ModuleInfo>{};
    for (var module in modules) {
      final serverPath = await _serverPathForModule(metadataProvider, module);
      if (serverPath == null) {
        _logger.warning('No module info found for module $module');
      } else {
        result[module] = ModuleInfo(
          // TODO: Save locations of full kernel files in ddc metadata.
          // Issue: https://github.com/dart-lang/sdk/issues/43684
          // TODO: Change these to URIs instead of paths when the SDK supports
          // it.
          p.setExtension(serverPath, '.full.dill'),
          p.setExtension(serverPath, '.dill'),
        );
      }
    }
    return result;
  }
}
