// Copyright (c) 2021, 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.

/// Implements support for dependency-bot style automated upgrades.
/// It is still work in progress - do not rely on the current output.
library;

import 'dart:convert';
import 'dart:io';

import 'package:collection/collection.dart';
import 'package:path/path.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart';
import 'package:yaml_edit/yaml_edit.dart';

import '../command.dart';
import '../entrypoint.dart';
import '../exceptions.dart';
import '../io.dart';
import '../lock_file.dart';
import '../log.dart' as log;
import '../package.dart';
import '../package_name.dart';
import '../pubspec.dart';
import '../pubspec_utils.dart';
import '../sdk.dart';
import '../solver.dart';
import '../solver/version_solver.dart';
import '../source/git.dart';
import '../source/hosted.dart';
import '../source/root.dart';
import '../system_cache.dart';
import '../utils.dart';

class DependencyServicesReportCommand extends PubCommand {
  @override
  String get name => 'report';
  @override
  String get description => 'Output a machine-digestible '
      'report of the upgrade options for each dependency.';
  @override
  String get argumentsDescription => '[options]';

  @override
  bool get takesArguments => false;

  DependencyServicesReportCommand() {
    argParser.addOption(
      'directory',
      abbr: 'C',
      help: 'Run this in the directory <dir>.',
      valueHelp: 'dir',
    );
  }

  @override
  Future<void> runProtected() async {
    _checkAtRoot(entrypoint);
    final stdinString = await utf8.decodeStream(stdin);
    final input = json.decode(stdinString.isEmpty ? '{}' : stdinString)
        as Map<String, Object?>;
    final additionalConstraints = _parseDisallowed(input, cache);
    final targetPackageName = input['target'];
    if (targetPackageName is! String?) {
      throw const FormatException('"target" should be a String.');
    }

    final compatibleWorkspace = entrypoint.workspaceRoot
        .transformWorkspace((p) => stripDependencyOverrides(p.pubspec));

    final breakingWorkspace = compatibleWorkspace.transformWorkspace(
      (p) => stripVersionBounds(p.pubspec),
    );

    final compatiblePackagesResult = await _tryResolve(
      compatibleWorkspace,
      cache,
      additionalConstraints: additionalConstraints,
    );

    final breakingPackagesResult = await _tryResolve(
      breakingWorkspace,
      cache,
      additionalConstraints: additionalConstraints,
    );

    final currentPackages = await _computeCurrentPackages(entrypoint, cache);

    final dependencies = <Object>[];
    final result = <String, Object>{'dependencies': dependencies};

    final targetPackage =
        targetPackageName == null ? null : currentPackages[targetPackageName];

    for (final package in targetPackage == null
        ? currentPackages.values
        : <PackageId>[targetPackage]) {
      final compatibleVersion = compatiblePackagesResult
          ?.firstWhereOrNull((element) => element.name == package.name);
      final multiBreakingVersion = breakingPackagesResult
          ?.firstWhereOrNull((element) => element.name == package.name);

      final kind = _kindString(compatibleWorkspace, package.name);
      PackageId? singleBreakingVersion;

      if (kind != 'transitive') {
        final singleBreakingWorkspace = compatibleWorkspace.transformWorkspace(
          (p) {
            final r = stripVersionBounds(p.pubspec, stripOnly: [package.name]);
            return r;
          },
        );
        final singleBreakingPackagesResult = await _tryResolve(
          singleBreakingWorkspace,
          cache,
        );
        singleBreakingVersion = singleBreakingPackagesResult
            ?.firstWhereOrNull((element) => element.name == package.name);
      }
      PackageId? smallestUpgrade;
      if (additionalConstraints.any(
        (c) => c.range.toRef() == package.toRef() && !c.range.allows(package),
      )) {
        // Current version disallowed by restrictions.
        final atLeastCurrentWorkspace = compatibleWorkspace.transformWorkspace(
          (p) => atLeastCurrent(
            p.pubspec,
            entrypoint.lockFile.packages.values.toList(),
          ),
        );

        final smallestUpgradeResult = await _tryResolve(
          atLeastCurrentWorkspace,
          cache,
          solveType: SolveType.downgrade,
          additionalConstraints: additionalConstraints,
        );

        smallestUpgrade = smallestUpgradeResult
            ?.firstWhereOrNull((element) => element.name == package.name);
      }

      Future<List<Object>> computeUpgradeSet(
        PackageId? package,
        _UpgradeType upgradeType,
      ) async {
        return await _computeUpgradeSet(
          compatibleWorkspace,
          package,
          entrypoint,
          cache,
          currentPackages: currentPackages,
          upgradeType: upgradeType,
          additionalConstraints: additionalConstraints,
        );
      }

      dependencies.add({
        'name': package.name,
        'version': package.versionOrHash(),
        'kind': kind,
        'source': _source(package, containingDir: directory),
        'latest':
            (await cache.getLatest(package.toRef(), version: package.version))
                ?.versionOrHash(),
        'constraint': _constraintIntersection(compatibleWorkspace, package.name)
            ?.toString(),
        'compatible': await computeUpgradeSet(
          compatibleVersion,
          _UpgradeType.compatible,
        ),
        'singleBreaking': kind != 'transitive' && singleBreakingVersion == null
            ? <Object>[]
            : await computeUpgradeSet(
                singleBreakingVersion,
                _UpgradeType.singleBreaking,
              ),
        'multiBreaking': kind != 'transitive' && multiBreakingVersion != null
            ? await computeUpgradeSet(
                multiBreakingVersion,
                _UpgradeType.multiBreaking,
              )
            : <Object>[],
        if (smallestUpgrade != null)
          'smallestUpdate': await computeUpgradeSet(
            smallestUpgrade,
            _UpgradeType.smallestUpdate,
          ),
      });
    }
    log.message(const JsonEncoder.withIndent('  ').convert(result));
  }
}

class DependencyServicesListCommand extends PubCommand {
  @override
  String get name => 'list';

  @override
  String get description =>
      'Output a machine digestible listing of all dependencies';

  @override
  bool get takesArguments => false;

  DependencyServicesListCommand() {
    argParser.addOption(
      'directory',
      abbr: 'C',
      help: 'Run this in the directory <dir>.',
      valueHelp: 'dir',
    );
  }

  @override
  Future<void> runProtected() async {
    _checkAtRoot(entrypoint);
    final currentPackages = fileExists(entrypoint.lockFilePath)
        ? entrypoint.lockFile.packages.values.toList()
        : (await _tryResolve(
              entrypoint.workspaceRoot,
              cache,
            ) ??
            <PackageId>[]);

    final dependencies = <Object>[];
    final result = <String, Object>{'dependencies': dependencies};

    for (final package in currentPackages.where((p) => !p.isRoot)) {
      dependencies.add({
        'name': package.name,
        'version': package.versionOrHash(),
        'kind': _kindString(entrypoint.workspaceRoot, package.name),
        'constraint':
            _constraintIntersection(entrypoint.workspaceRoot, package.name)
                ?.toString(),
        'source': _source(package, containingDir: directory),
      });
    }
    log.message(const JsonEncoder.withIndent('  ').convert(result));
  }
}

extension on PackageId {
  String versionOrHash() {
    final description = this.description;
    if (description is ResolvedGitDescription) {
      return description.resolvedRef;
    } else {
      return version.toString();
    }
  }
}

enum _UpgradeType {
  /// Only upgrade pubspec.lock.
  compatible,

  /// Unlock at most one dependency in pubspec.yaml.
  singleBreaking,

  /// Unlock any dependencies in pubspec.yaml needed for getting the
  /// latest resolvable version.
  multiBreaking,

  /// Try to upgrade as little as possible.
  smallestUpdate,
}

class DependencyServicesApplyCommand extends PubCommand {
  @override
  String get name => 'apply';

  @override
  String get description =>
      'Updates pubspec.yaml and pubspec.lock according to input.';

  @override
  bool get takesArguments => true;

  DependencyServicesApplyCommand() {
    argParser.addOption(
      'directory',
      abbr: 'C',
      help: 'Run this in the directory <dir>.',
      valueHelp: 'dir',
    );
  }

  @override
  Future<void> runProtected() async {
    final toApply = <_PackageVersion>[];
    final input = json.decode(await utf8.decodeStream(stdin));
    if (input is! Map<String, dynamic>) {
      fail('Bad input, must be json map');
    }
    final dependencyChanges = input['dependencyChanges'];
    if (dependencyChanges is! List) {
      fail('Bad input. `dependencyChanges` must be a list');
    }
    for (final change in dependencyChanges) {
      if (change is! Map<String, dynamic>) {
        fail('Bad input. Each element of `dependencyChanges` must be a map.');
      }
      toApply.add(
        _PackageVersion(
          change['name'] as String,
          change['version'] as String?,
          change['constraint'] != null
              ? VersionConstraint.parse(change['constraint'] as String)
              : null,
        ),
      );
    }
    final updatedPubspecs = <String, YamlEditor>{};
    _checkAtRoot(entrypoint);
    for (final package in entrypoint.workspaceRoot.transitiveWorkspace) {
      final pubspec = package.pubspec;
      final pubspecEditor = YamlEditor(readTextFile(package.pubspecPath));
      for (final p in toApply) {
        final targetConstraint = p.constraint;
        final targetPackage = p.name;
        final targetVersion = p.version;
        late final section = pubspec.dependencies[targetPackage] != null
            ? 'dependencies'
            : pubspec.devDependencies[targetPackage] != null
                ? 'dev_dependencies'
                : null;
        if (section != null) {
          if (targetConstraint != null) {
            final packageConfig =
                pubspecEditor.parseAt([section, targetPackage]).value;
            if (packageConfig == null || packageConfig is String) {
              pubspecEditor.update(
                [section, targetPackage],
                targetConstraint.toString(),
              );
            } else if (packageConfig is Map) {
              pubspecEditor.update(
                [section, targetPackage, 'version'],
                targetConstraint.toString(),
              );
            } else {
              fail(
                'The dependency $targetPackage does not have a '
                'map or string as a description',
              );
            }
          } else if (targetVersion != null) {
            final constraint = _constraintOf(pubspec, targetPackage);
            if (constraint != null && !constraint.allows(targetVersion)) {
              pubspecEditor.update(
                [section, targetPackage],
                VersionConstraint.compatibleWith(targetVersion).toString(),
              );
            }
          }
        }
        updatedPubspecs[package.dir] = pubspecEditor;
      }
    }
    final lockFile = fileExists(entrypoint.lockFilePath)
        ? readTextFile(entrypoint.lockFilePath)
        : null;
    final lockFileYaml = lockFile == null ? null : loadYaml(lockFile);

    final lockFileEditor = lockFile == null ? null : YamlEditor(lockFile);
    final hasContentHashes = _lockFileHasContentHashes(lockFileYaml);
    final usesPubDev = _lockFileUsesPubDev(lockFileYaml);
    for (final p in toApply) {
      final targetPackage = p.name;
      final targetVersion = p.version;
      final targetRevision = p.gitRevision;

      if (lockFileEditor != null) {
        if (lockFileYaml is! Map) {
          fail('Malformed pubspec.lock. Must be a map');
        }
        if (targetVersion != null &&
            (lockFileYaml['packages'] as Map).containsKey(targetPackage)) {
          lockFileEditor.update(
            ['packages', targetPackage, 'version'],
            targetVersion.toString(),
          );
          // Remove the now outdated content-hash - it will be restored below
          // after resolution.
          final packageMap = lockFileEditor
              .parseAt(['packages', targetPackage, 'description']).value as Map;
          final hasSha = packageMap.containsKey('sha256');
          if (hasSha) {
            lockFileEditor.remove(
              ['packages', targetPackage, 'description', 'sha256'],
            );
          }
        } else if (targetRevision != null &&
            (lockFileYaml['packages'] as Map).containsKey(targetPackage)) {
          final ref = entrypoint.lockFile.packages[targetPackage]!.toRef();
          final currentDescription = ref.description as GitDescription;
          final updatedRef = PackageRef(
            targetPackage,
            GitDescription(
              url: currentDescription.url,
              path: currentDescription.path,
              ref: targetRevision,
              containingDir: directory,
            ),
          );
          final versions = await cache.getVersions(updatedRef);
          if (versions.isEmpty) {
            dataError(
              'Found no versions of $targetPackage '
              'with git revision `$targetRevision`.',
            );
          }
          // GitSource can only return a single version.
          assert(versions.length == 1);

          lockFileEditor.update(
            ['packages', targetPackage, 'version'],
            versions.single.version.toString(),
          );
          lockFileEditor.update(
            ['packages', targetPackage, 'description', 'resolved-ref'],
            targetRevision,
          );
        } else if (targetVersion == null &&
            targetRevision == null &&
            !(lockFileYaml['packages'] as Map).containsKey(targetPackage)) {
          dataError(
            'Trying to remove non-existing '
            'transitive dependency $targetPackage.',
          );
        }
      }
    }

    final updatedLockfile = lockFileEditor == null
        ? null
        : LockFile.parse(
            lockFileEditor.toString(),
            cache.sources,
            filePath: entrypoint.lockFilePath,
          );
    await log.errorsOnlyUnlessTerminal(
      () async {
        final updatedWorkspace = entrypoint.workspaceRoot.transformWorkspace(
          (package) => Pubspec.parse(
            updatedPubspecs[package.dir].toString(),
            cache.sources,
            location: toUri(package.pubspecPath),
            containingDescription: RootDescription(package.dir),
          ),
        );
        // Resolve versions, this will update transitive dependencies that were
        // not passed in the input. And also counts as a validation of the input
        // by ensuring the resolution is valid.
        //
        // We don't use `acquireDependencies` as that downloads all the archives
        // to cache.
        // TODO: Handle HTTP exceptions gracefully!
        final solveResult = await resolveVersions(
          SolveType.get,
          cache,
          updatedWorkspace,
          lockFile: updatedLockfile,
        );
        for (final package in entrypoint.workspaceRoot.transitiveWorkspace) {
          final updatedPubspec = updatedPubspecs[package.dir]!;
          if (updatedPubspec.edits.isNotEmpty) {
            writeTextFile(
              package.pubspecPath,
              updatedPubspec.toString(),
            );
          }
        }
        // Only if we originally had a lock-file we write the resulting lockfile
        // back.
        if (updatedLockfile != null) {
          final updatedPackages = <PackageId>[];
          for (var package in solveResult.packages) {
            if (package.isRoot) continue;
            final description = package.description;
            // Handle content-hashes of hosted dependencies.
            if (description is ResolvedHostedDescription) {
              // Ensure we get content-hashes if the original lock-file had
              // them.
              if (hasContentHashes) {
                if (description.sha256 == null) {
                  // We removed the hash above before resolution - as we get the
                  // locked id back we need to find the content-hash from the
                  // version listing.
                  //
                  // `pub get` gets this version-listing from the downloaded
                  // archive but we don't want to download all archives - so we
                  // copy it from the version listing.
                  package = (await cache.getVersions(package.toRef()))
                      .firstWhere((id) => id == package, orElse: () => package);
                  if ((package.description as ResolvedHostedDescription)
                          .sha256 ==
                      null) {
                    // This happens when we resolved a package from a legacy
                    // server not providing archive_sha256. As a side-effect of
                    // downloading the package we compute and store the sha256.
                    package = (await cache.downloadPackage(package)).packageId;
                  }
                }
              } else {
                // The original pubspec.lock did not have content-hashes. Remove
                // any content hash, so we don't start adding them.
                package = PackageId(
                  package.name,
                  package.version,
                  description.withSha256(null),
                );
              }
              // Keep using https://pub.dartlang.org if the original lockfile
              // used it. This is to support lockfiles from old sdks.
              if (!usesPubDev &&
                  HostedSource.isPubDevUrl(description.description.url)) {
                package = PackageId(
                  package.name,
                  package.version,
                  ResolvedHostedDescription(
                    HostedDescription.raw(
                      package.name,
                      HostedSource.pubDartlangUrl,
                    ),
                    sha256: (package.description as ResolvedHostedDescription)
                        .sha256,
                  ),
                );
              }
            }
            updatedPackages.add(package);
          }

          final newLockFile = LockFile(
            updatedPackages,
            sdkConstraints: updatedLockfile.sdkConstraints,
            mainDependencies: entrypoint.lockFile.mainDependencies,
            devDependencies: entrypoint.lockFile.devDependencies,
            overriddenDependencies: entrypoint.lockFile.overriddenDependencies,
          );

          newLockFile.writeToFile(entrypoint.lockFilePath, cache);
        }
      },
    );
    // Dummy message.
    log.message(json.encode({'dependencies': <Object>[]}));
  }
}

void _checkAtRoot(Entrypoint entrypoint) {
  if (entrypoint.workspaceRoot != entrypoint.workPackage) {
    fail('Only apply dependency_services to the root of the workspace.');
  }
}

class _PackageVersion {
  String name;
  Version? version;
  String? gitRevision;
  VersionConstraint? constraint;
  _PackageVersion(this.name, String? versionOrHash, this.constraint)
      : version =
            versionOrHash == null ? null : _tryParseVersion(versionOrHash),
        gitRevision =
            versionOrHash == null ? null : _tryParseHash(versionOrHash);
}

Version? _tryParseVersion(String v) {
  try {
    return Version.parse(v);
  } on FormatException {
    return null;
  }
}

String? _tryParseHash(String v) {
  if (RegExp(r'^[a-fA-F0-9]+$').hasMatch(v)) {
    return v;
  }
  return null;
}

Map<String, PackageRange>? _dependencySetOfPackage(
  Pubspec pubspec,
  PackageId package,
) {
  return pubspec.dependencies.containsKey(package.name)
      ? pubspec.dependencies
      : pubspec.devDependencies.containsKey(package.name)
          ? pubspec.devDependencies
          : null;
}

/// Return a constraint compatible with [newVersion].
///
/// By convention if the original constraint is pinned we return [newVersion].
/// Otherwise use [VersionConstraint.compatibleWith].
VersionConstraint _bumpConstraint(
  VersionConstraint original,
  Version newVersion,
) {
  if (original.isEmpty) return newVersion;
  if (original is VersionRange) {
    if (original.min == original.max) return newVersion;

    return VersionConstraint.compatibleWith(newVersion);
  }

  throw ArgumentError.value(
    original,
    'original',
    'Must be a Version range or empty',
  );
}

/// Return a constraint compatible with [newVersion], but including [original]
/// as well.
///
/// By convention if the original constraint is pinned, we don't widen the
/// constraint but return [newVersion] instead.
VersionConstraint _widenConstraint(
  VersionConstraint original,
  Version newVersion,
) {
  if (original.allows(newVersion)) return original;
  if (original is VersionRange) {
    final min = original.min;
    final max = original.max;
    if (min == max) return newVersion;
    if (max != null && newVersion >= max) {
      return _compatibleWithIfPossible(
        VersionRange(
          min: min,
          includeMin: original.includeMin,
          max: newVersion.nextBreaking.firstPreRelease,
        ),
      );
    }
    if (min != null && newVersion <= min) {
      return _compatibleWithIfPossible(
        VersionRange(
          min: newVersion,
          includeMin: true,
          max: max,
          includeMax: original.includeMax,
        ),
      );
    }
  }

  if (original.isEmpty) return newVersion;
  throw ArgumentError.value(
    original,
    'original',
    'Must be a Version range or empty',
  );
}

VersionConstraint _compatibleWithIfPossible(VersionRange versionRange) {
  final min = versionRange.min;
  if (min != null && min.nextBreaking.firstPreRelease == versionRange.max) {
    return VersionConstraint.compatibleWith(min);
  }
  return versionRange;
}

/// `true` iff any of the packages described by the [lockfile] has a
/// content-hash.
///
/// Undefined for invalid lock files, but mostly `true`.
bool _lockFileHasContentHashes(dynamic lockfile) {
  if (lockfile is! Map) return true;
  final packages = lockfile['packages'];
  if (packages is! Map) return true;

  /// We consider an empty lockfile ready to get content-hashes.
  if (packages.isEmpty) return true;
  for (final package in packages.values) {
    if (package is! Map) return true;
    final descriptor = package['description'];
    if (descriptor is! Map) return true;
    if (descriptor['sha256'] != null) return true;
  }
  return false;
}

/// Try to solve [package] return [PackageId]s in the resolution or `null` if no
/// resolution was found.
Future<List<PackageId>?> _tryResolve(
  Package package,
  SystemCache cache, {
  SolveType solveType = SolveType.upgrade,
  Iterable<ConstraintAndCause>? additionalConstraints,
}) async {
  final solveResult = await tryResolveVersions(
    solveType,
    cache,
    package,
    additionalConstraints: additionalConstraints,
  );

  return solveResult?.packages;
}

VersionConstraint? _constraintIntersection(
  Package workspace,
  String packageName,
) {
  final constraints = workspace.transitiveWorkspace
      .map((p) => _constraintOf(p.pubspec, packageName))
      .nonNulls;
  if (constraints.isEmpty) {
    return null;
  }
  return constraints
      .reduce((a, b) => a.intersect(b))
      .asCompatibleWithIfPossible();
}

VersionConstraint? _constraintOf(Pubspec pubspec, String packageName) {
  return (pubspec.dependencies[packageName] ??
          pubspec.devDependencies[packageName])
      ?.constraint;
}

String _kindString(Package workspace, String packageName) {
  return workspace.transitiveWorkspace
          .any((p) => p.dependencies.containsKey(packageName))
      ? 'direct'
      : workspace.transitiveWorkspace
              .any((p) => p.devDependencies.containsKey(packageName))
          ? 'dev'
          : 'transitive';
}

Map<String, Object?> _source(PackageId id, {required String containingDir}) {
  return {
    'type': id.source.name,
    'description':
        id.description.serializeForLockfile(containingDir: containingDir),
  };
}

/// The packages in the current lockfile or resolved from current pubspec.yaml.
/// Does not include the root package.
Future<Map<String, PackageId>> _computeCurrentPackages(
  Entrypoint entrypoint,
  SystemCache cache,
) async {
  late Map<String, PackageId> currentPackages;

  if (fileExists(entrypoint.lockFilePath)) {
    currentPackages = Map<String, PackageId>.from(entrypoint.lockFile.packages);
  } else {
    final resolution = await _tryResolve(entrypoint.workspaceRoot, cache) ??
        (throw DataException('Failed to resolve pubspec'));
    currentPackages = Map<String, PackageId>.fromIterable(
      resolution,
      key: (e) => (e as PackageId).name,
    );
  }
  for (final p in entrypoint.workspaceRoot.transitiveWorkspace) {
    currentPackages.remove(p.name);
  }
  return currentPackages;
}

Future<List<Object>> _computeUpgradeSet(
  Package workspace,
  PackageId? package,
  Entrypoint entrypoint,
  SystemCache cache, {
  required Map<String, PackageId> currentPackages,
  required _UpgradeType upgradeType,
  required List<ConstraintAndCause> additionalConstraints,
}) async {
  if (package == null) return [];
  final lockFile = entrypoint.lockFile;
  final upgradedWorkspace = (upgradeType == _UpgradeType.multiBreaking ||
          upgradeType == _UpgradeType.smallestUpdate)
      ? workspace.transformWorkspace((p) => stripVersionBounds(p.pubspec))
      : workspace.transformWorkspace((p) => p.pubspec.copyWith());

  for (final p in upgradedWorkspace.transitiveWorkspace) {
    final dependencySet = _dependencySetOfPackage(p.pubspec, package);
    if (dependencySet != null) {
      // Force the version to be the new version.
      dependencySet[package.name] =
          package.toRef().withConstraint(package.toRange().constraint);
    }
  }

  final resolution = await tryResolveVersions(
    upgradeType == _UpgradeType.smallestUpdate
        ? SolveType.downgrade
        : SolveType.get,
    cache,
    upgradedWorkspace,
    lockFile: lockFile,
    additionalConstraints: additionalConstraints,
  );

  // TODO(sigurdm): improve error messages.
  if (resolution == null) {
    return [];
  }
  final workspaceNames = {
    ...workspace.transitiveWorkspace.map((p) => p.name),
  };
  return [
    ...resolution.packages.where((r) {
      if (workspaceNames.contains(r.name)) return false;
      final originalVersion = currentPackages[r.name];
      return originalVersion == null || r != originalVersion;
    }).map((p) {
      final constraintIntersection = _constraintIntersection(workspace, p.name);
      final currentPackage = currentPackages[p.name];
      return {
        'name': p.name,
        'version': p.versionOrHash(),
        'kind': _kindString(workspace, p.name),
        'source': _source(p, containingDir: entrypoint.workspaceRoot.dir),
        'constraintBumped': constraintIntersection == null
            ? null
            : upgradeType == _UpgradeType.compatible
                ? constraintIntersection.toString()
                : _bumpConstraint(constraintIntersection, p.version).toString(),
        'constraintWidened': constraintIntersection == null
            ? null
            : upgradeType == _UpgradeType.compatible
                ? constraintIntersection.toString()
                : _widenConstraint(constraintIntersection, p.version)
                    .toString(),
        'constraintBumpedIfNeeded': constraintIntersection == null
            ? null
            : upgradeType == _UpgradeType.compatible
                ? constraintIntersection.toString()
                : constraintIntersection.allows(p.version)
                    ? constraintIntersection.toString()
                    : _bumpConstraint(constraintIntersection, p.version)
                        .toString(),
        'previousVersion': currentPackage?.versionOrHash(),
        'previousConstraint': constraintIntersection?.toString(),
        'previousSource': currentPackage == null
            ? null
            : _source(
                currentPackage,
                containingDir: entrypoint.workspaceRoot.dir,
              ),
      };
    }),
    // Find packages that were removed by the resolution
    for (final oldPackageName in lockFile.packages.keys)
      if (!resolution.packages
          .any((newPackage) => newPackage.name == oldPackageName))
        {
          'name': oldPackageName,
          'version': null,
          'kind': 'transitive', // Only transitive constraints can be removed.
          'constraintBumped': null,
          'constraintWidened': null,
          'constraintBumpedIfNeeded': null,
          'previousVersion': currentPackages[oldPackageName]?.versionOrHash(),
          'previousConstraint': null,
          'previous': _source(
            currentPackages[oldPackageName]!,
            containingDir: entrypoint.workspaceRoot.dir,
          ),
        },
  ];
}

List<ConstraintAndCause> _parseDisallowed(
  Map<String, Object?> input,
  SystemCache cache,
) {
  final disallowedList = input['disallowed'];
  if (disallowedList == null) {
    return [];
  }
  if (disallowedList is! List<Object?>) {
    throw const FormatException('Disallowed should be a list of maps');
  }
  final result = <ConstraintAndCause>[];
  for (final disallowed in disallowedList) {
    if (disallowed is! Map) {
      throw const FormatException('Disallowed should be a list of maps');
    }
    final name = disallowed['name'];
    if (name is! String) {
      throw const FormatException('"name" should be a string.');
    }
    final url = disallowed['url'] ?? cache.hosted.defaultUrl;
    if (url is! String) {
      throw const FormatException('"url" should be a string.');
    }
    final ref = PackageRef(
      name,
      HostedDescription(
        name,
        url,
      ),
    );
    final constraints = disallowed['versions'];
    if (constraints is! List) {
      throw const FormatException('"versions" should be a list.');
    }
    final reason = disallowed['reason'];
    if (reason is! String?) {
      throw const FormatException('"reason", if present, should be a string.');
    }
    for (final entry in constraints) {
      if (entry is! Map) {
        throw const FormatException(
          'Each element of "versions" should be an object.',
        );
      }
      final rangeString = entry['range'];
      if (rangeString is! String) {
        throw const FormatException('"range" should be a string');
      }
      final range = VersionConstraint.parse(rangeString);
      result.add(
        ConstraintAndCause(
          PackageRange(ref, VersionConstraint.any.difference(range)),
          reason,
        ),
      );
    }
  }
  return result;
}

/// `true` iff any of the packages described by the [lockfile] uses
/// `https://pub.dev` as url.
///
/// Undefined for invalid lock files, but mostly `true`.
bool _lockFileUsesPubDev(dynamic lockfile) {
  if (lockfile is! Map) return true;
  final packages = lockfile['packages'];
  if (packages is! Map) return true;

  /// We consider an empty lockfile ready to get content-hashes.
  if (packages.isEmpty) return true;
  for (final package in packages.values) {
    if (package is! Map) return true;
    if (package['source'] != 'hosted') continue;
    final descriptor = package['description'];
    if (descriptor is! Map) return true;
    final url = descriptor['url'];
    if (url is! String) return true;
    if (HostedSource.isPubDevUrl(url) && url != HostedSource.pubDartlangUrl) {
      return true;
    }
  }
  return false;
}
