// Copyright (c) 2013, 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:async' show Future;
import 'dart:convert' show JsonEncoder, json, utf8;
import 'dart:io' show File;

import 'package:path/path.dart' as p;
import 'package:pub/src/package_config.dart';
import 'package:pub/src/packages_file.dart' as packages_file;
import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart';

import '../test_pub.dart';

// Resolve against a dummy URL so that we can test whether the URLs in
// the package file are themselves relative. We can't resolve against just
// "." due to sdk#23809.
const _base = '/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p';

/// Describes a `.packages` file and its contents.
class PackagesFileDescriptor extends Descriptor {
  /// A map from package names to either version strings or path to the package.
  final Map<String, String>? _dependencies;

  /// Describes a `.packages` file with the given dependencies.
  ///
  /// [dependencies] maps package names to strings describing where the packages
  /// are located on disk.
  PackagesFileDescriptor([this._dependencies]) : super('.packages');

  @override
  Future create([String? parent]) {
    var contents = const <int>[];
    var dependencies = _dependencies;
    if (dependencies != null) {
      var mapping = <String, Uri>{};
      dependencies.forEach((package, version) {
        String packagePath;
        if (_isSemver(version)) {
          // It's a cache reference.
          packagePath = p.join(cachePath, '$package-$version');
        } else {
          // Otherwise it's a path relative to the pubspec file,
          // which is also relative to the .packages file.
          packagePath = version;
        }
        mapping[package] = p.toUri(p.join(packagePath, 'lib', ''));
      });
      var buffer = StringBuffer();
      packages_file.write(buffer, mapping);
      contents = utf8.encode(buffer.toString());
    }
    return File(p.join(parent ?? sandbox, name)).writeAsBytes(contents);
  }

  @override
  Future validate([String? parent]) async {
    var fullPath = p.join(parent ?? sandbox, name);
    if (!await File(fullPath).exists()) {
      fail("File not found: '$fullPath'.");
    }

    var bytes = await File(fullPath).readAsBytes();

    var map = packages_file.parse(bytes, Uri.parse(_base));

    var dependencies = _dependencies!;

    for (var package in dependencies.keys) {
      if (!map.containsKey(package)) {
        fail('.packages does not contain $package entry');
      }

      var description = dependencies[package]!;
      if (_isSemver(description)) {
        if (!map[package]!.path.contains(description)) {
          fail('.packages of $package has incorrect version. '
              'Expected $description, found location: ${map[package]}.');
        }
      } else {
        var expected = p.normalize(p.join(description, 'lib'));
        var actual = p.normalize(p.fromUri(
            p.url.relative(map[package].toString(), from: p.dirname(_base))));

        if (expected != actual) {
          fail('Relative path: Expected $expected, found $actual');
        }
      }
    }

    if (map.length != dependencies.length) {
      for (var key in map.keys) {
        if (!dependencies.containsKey(key)) {
          fail('.packages file contains unexpected entry: $key');
        }
      }
    }
  }

  @override
  String describe() => name;
}

/// Describes a `.dart_tools/package_config.json` file and its contents.
class PackageConfigFileDescriptor extends Descriptor {
  final String _generatorVersion;

  /// A map describing the packages in this `package_config.json` file.
  final List<PackageConfigEntry> _packages;

  PackageConfig get _config {
    return PackageConfig(
      configVersion: 2,
      packages: _packages,
      generatorVersion: Version.parse(_generatorVersion),
      generator: 'pub',
      generated: DateTime.now().toUtc(),
    );
  }

  /// Describes a `.packages` file with the given dependencies.
  ///
  /// [dependencies] maps package names to strings describing where the packages
  /// are located on disk.
  PackageConfigFileDescriptor(this._packages, this._generatorVersion)
      : super('.dart_tool/package_config.json');

  @override
  Future<void> create([String? parent]) async {
    final packageConfigFile = File(p.join(parent ?? sandbox, name));
    await packageConfigFile.parent.create();
    await packageConfigFile.writeAsString(
      const JsonEncoder.withIndent('  ').convert(_config.toJson()) + '\n',
    );
  }

  @override
  Future<void> validate([String? parent]) async {
    final packageConfigFile = p.join(parent ?? sandbox, name);
    if (!await File(packageConfigFile).exists()) {
      fail("File not found: '$packageConfigFile'.");
    }

    Map<String, dynamic> rawJson = json.decode(
      await File(packageConfigFile).readAsString(),
    );
    PackageConfig config;
    try {
      config = PackageConfig.fromJson(rawJson);
    } on FormatException catch (e) {
      fail('File "$packageConfigFile" is not valid: $e');
    }

    // Compare packages as sets to ignore ordering.
    expect(
      config.packages.map((e) => e.toJson()).toSet(),
      equals(_packages.map((e) => e.toJson()).toSet()),
      reason:
          '"packages" property in "$packageConfigFile" does not expected values',
    );

    final expected = PackageConfig.fromJson(_config.toJson());
    // omit generated date-time and packages
    expected.generated = null; // comparing timestamps is unnecessary.
    config.generated = null;
    expected.packages = []; // Already compared packages (ignoring ordering)
    config.packages = [];
    expect(config.toJson(), equals(expected.toJson()),
        reason: '"$packageConfigFile" does not match expected values');
  }

  @override
  String describe() => name;
}

/// Returns `true` if [text] is a valid semantic version number string.
bool _isSemver(String text) {
  try {
    // See if it's a semver.
    Version.parse(text);
    return true;
  } on FormatException catch (_) {
    // Do nothing.
  }
  return false;
}
