// 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:io' as io
    show
        Directory,
        File,
        FileStat,
        FileSystemEntity,
        FileSystemEntityType,
        Link;

import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p; // flutter_ignore: package_path_import

/// A [FileSystem] that wraps the [delegate] file system to create an overlay of
/// files from multiple [roots].
///
/// Regular paths or `file:` URIs are resolved directly in the underlying file
/// system, but URIs that use a special [scheme] are resolved by searching
/// under a set of given roots in order.
///
/// For example, consider the following inputs:
///
///   - scheme is `multi-root`
///   - the set of roots are `/a` and `/b`
///   - the underlying file system contains files:
///         /root_a/dir/only_a.dart
///         /root_a/dir/both.dart
///         /root_b/dir/only_b.dart
///         /root_b/dir/both.dart
///         /other/other.dart
///
/// Then:
///
///   - file:///other/other.dart is resolved as /other/other.dart
///   - multi-root:///dir/only_a.dart is resolved as /root_a/dir/only_a.dart
///   - multi-root:///dir/only_b.dart is resolved as /root_b/dir/only_b.dart
///   - multi-root:///dir/both.dart is resolved as /root_a/dir/only_a.dart
class MultiRootFileSystem extends ForwardingFileSystem {
  MultiRootFileSystem({
    required FileSystem delegate,
    required String scheme,
    required List<String> roots,
  })   : assert(delegate != null),
        assert(roots.isNotEmpty),
        _scheme = scheme,
        _roots = roots.map((String root) => delegate.path.normalize(root)).toList(),
        super(delegate);

  @visibleForTesting
  FileSystem get fileSystem => delegate;

  final String _scheme;
  final List<String> _roots;

  @override
  File file(dynamic path) => MultiRootFile(
    fileSystem: this,
    delegate: delegate.file(_resolve(path)),
  );

  @override
  Directory directory(dynamic path) => MultiRootDirectory(
    fileSystem: this,
    delegate: delegate.directory(_resolve(path)),
  );

  @override
  Link link(dynamic path) => MultiRootLink(
    fileSystem: this,
    delegate: delegate.link(_resolve(path)),
  );

  @override
  Future<io.FileStat> stat(String path) =>
    delegate.stat(_resolve(path).toString());

  @override
  io.FileStat statSync(String path) =>
    delegate.statSync(_resolve(path).toString());

  @override
  Future<bool> identical(String path1, String path2) =>
    delegate.identical(_resolve(path1).toString(), _resolve(path2).toString());

  @override
  bool identicalSync(String path1, String path2) =>
    delegate.identicalSync(_resolve(path1).toString(), _resolve(path2).toString());

  @override
  Future<io.FileSystemEntityType> type(String path, {bool followLinks = true}) =>
    delegate.type(_resolve(path).toString(), followLinks: followLinks);

  @override
  io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) =>
    delegate.typeSync(_resolve(path).toString(), followLinks: followLinks);

  // Caching the path context here and clearing when the currentDirectory setter
  // is updated works since the flutter tool restricts usage of dart:io directly
  // via the forbidden import tests. Otherwise, the path context's current
  // working directory might get out of sync, leading to unexpected results from
  // methods like `path.relative`.
  @override
  p.Context get path => _cachedPath ??= delegate.path;
  p.Context? _cachedPath;

  @override
  set currentDirectory(dynamic path) {
    _cachedPath = null;
    delegate.currentDirectory = path;
  }

  /// If the path is a multiroot uri, resolve to the actual path of the
  /// underlying file system. Otherwise, return as is.
  dynamic _resolve(dynamic path) {
    Uri uri;
    if (path == null) {
      return null;
    } else if (path is String) {
      uri = Uri.parse(path);
    } else if (path is Uri) {
      uri = path;
    } else if (path is FileSystemEntity) {
      uri = path.uri;
    } else {
      throw ArgumentError('Invalid type for "path": ${(path as Object?)?.runtimeType}');
    }

    if (!uri.hasScheme || uri.scheme != _scheme) {
      return path;
    }

    String? firstRootPath;
    final String relativePath = delegate.path.joinAll(uri.pathSegments);
    for (final String root in _roots) {
      final String pathWithRoot = delegate.path.join(root, relativePath);
      if (delegate.typeSync(pathWithRoot, followLinks: false) !=
          FileSystemEntityType.notFound) {
        return pathWithRoot;
      }
      firstRootPath ??= pathWithRoot;
    }

    // If not found, construct the path with the first root.
    return firstRootPath!;
  }

  Uri _toMultiRootUri(Uri uri) {
    if (uri.scheme != 'file') {
      return uri;
    }

    final p.Context pathContext = delegate.path;
    final bool isWindows = pathContext.style == p.Style.windows;
    final String path = uri.toFilePath(windows: isWindows);
    for (final String root in _roots) {
      if (path.startsWith('$root${pathContext.separator}')) {
        String pathWithoutRoot = path.substring(root.length + 1);
        if (isWindows) {
          // Convert the path from Windows style
          pathWithoutRoot = p.url.joinAll(pathContext.split(pathWithoutRoot));
        }
        return Uri.parse('$_scheme:///$pathWithoutRoot');
      }
    }
    return uri;
  }

  @override
  String toString() =>
    'MultiRootFileSystem(scheme = $_scheme, roots = $_roots, delegate = $delegate)';
}

abstract class MultiRootFileSystemEntity<T extends FileSystemEntity,
    D extends io.FileSystemEntity> extends ForwardingFileSystemEntity<T, D> {
  MultiRootFileSystemEntity({
    required this.fileSystem,
    required this.delegate,
  });

  @override
  final D delegate;

  @override
  final MultiRootFileSystem fileSystem;

  @override
  File wrapFile(io.File delegate) => MultiRootFile(
    fileSystem: fileSystem,
    delegate: delegate,
  );

  @override
  Directory wrapDirectory(io.Directory delegate) => MultiRootDirectory(
    fileSystem: fileSystem,
    delegate: delegate,
  );

  @override
  Link wrapLink(io.Link delegate) => MultiRootLink(
    fileSystem: fileSystem,
    delegate: delegate,
  );

  @override
  Uri get uri => fileSystem._toMultiRootUri(delegate.uri);
}

class MultiRootFile extends MultiRootFileSystemEntity<File, io.File>
    with ForwardingFile {
  MultiRootFile({
    required super.fileSystem,
    required super.delegate,
  });

  @override
  String toString() =>
    'MultiRootFile(fileSystem = $fileSystem, delegate = $delegate)';
}

class MultiRootDirectory
    extends MultiRootFileSystemEntity<Directory, io.Directory>
    with ForwardingDirectory<Directory> {
  MultiRootDirectory({
    required super.fileSystem,
    required super.delegate,
  });

  // For the childEntity methods, we first obtain an instance of the entity
  // from the underlying file system, then invoke childEntity() on it, then
  // wrap in the ErrorHandling version.
  @override
  Directory childDirectory(String basename) =>
    fileSystem.directory(fileSystem.path.join(delegate.path, basename));

  @override
  File childFile(String basename) =>
    fileSystem.file(fileSystem.path.join(delegate.path, basename));

  @override
  Link childLink(String basename) =>
    fileSystem.link(fileSystem.path.join(delegate.path, basename));

  @override
  String toString() =>
    'MultiRootDirectory(fileSystem = $fileSystem, delegate = $delegate)';
}

class MultiRootLink extends MultiRootFileSystemEntity<Link, io.Link>
    with ForwardingLink {
  MultiRootLink({
    required super.fileSystem,
    required super.delegate,
  });

  @override
  String toString() =>
    'MultiRootLink(fileSystem = $fileSystem, delegate = $delegate)';
}
