// Copyright (c) 2014, 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.
// TODO(rnystrom): Merge with mac_os version.

import 'dart:async';
import 'dart:collection';
import 'dart:io';

import 'package:path/path.dart' as p;

import '../directory_watcher.dart';
import '../event.dart';
import '../path_set.dart';
import '../resubscribable.dart';
import '../watch_event.dart';
import 'directory_list.dart';

class WindowsDirectoryWatcher extends ResubscribableWatcher
    implements DirectoryWatcher {
  @override
  String get directory => path;

  WindowsDirectoryWatcher(String directory)
      : super(
            directory, () => WindowsManuallyClosedDirectoryWatcher(directory));
}

/// Windows directory watcher.
///
/// On Windows the OS file change notifications do not include whether the
/// file system entity is a directory. So, the Dart VM checks the filesystem
/// after the event is received to get the type. This leads to the `isDirectory`
/// value being unreliable in two important ways.
///
/// 1. If the event is about a filesystem entity that gets deleted immediately
/// after the event then the Dart VM finds nothing and just reports
/// `false` for `isDirectory`.
///
/// 2. If the event is about a newly-created link to a directory then the file
/// system entity type changes during creation from directory to link. The Dart
/// VM entity type check races with this, and the VM reports a random value for
/// `isDirectory`. See: https://github.com/dart-lang/sdk/issues/61797
///
/// To deal with both, `isDirectory` is discarded and the filesystem is checked
/// again after a sufficient delay to allow directory symlink creation to
/// finish.
///
/// On my machine, the test failure rate due to the type drops from 150/1000
/// at 900us to 0/10000 at 1000us. So, 1000us = 1ms is sufficient. Use 5ms to
/// give a margin for error for different machine performance and load.
class WindowsManuallyClosedDirectoryWatcher
    implements DirectoryWatcher, ManuallyClosedWatcher {
  @override
  String get directory => path;
  @override
  final String path;

  @override
  Stream<WatchEvent> get events => _eventsController.stream;
  final _eventsController = StreamController<WatchEvent>.broadcast();

  @override
  bool get isReady => _readyCompleter.isCompleted;

  @override
  Future<void> get ready => _readyCompleter.future;
  final _readyCompleter = Completer<void>();

  final Map<String, _PendingPoll> _pendingPolls =
      HashMap<String, _PendingPoll>();

  /// The set of files that are known to exist recursively within the watched
  /// directory.
  ///
  /// The state of files on the filesystem is compared against this to determine
  /// the real change that occurred. This is also used to emit REMOVE events
  /// when subdirectories are moved out of the watched directory.
  final PathSet _files;

  /// The subscription to the stream returned by [Directory.watch].
  StreamSubscription<FileSystemEvent>? _watchSubscription;

  /// The subscription to the stream returned by [Directory.watch] of the
  /// parent directory to [directory]. This is needed to detect changes to
  /// [directory], as they are not included on Windows.
  StreamSubscription<FileSystemEvent>? _parentWatchSubscription;

  /// The subscription to the [Directory.list] call for the initial listing of
  /// the directory to determine its initial state.
  StreamSubscription<FileSystemEntity>? _initialListSubscription;

  /// The subscriptions to the [Directory.list] calls for listing the contents
  /// of subdirectories that were moved into the watched directory.
  final Set<StreamSubscription<FileSystemEntity>> _listSubscriptions =
      HashSet<StreamSubscription<FileSystemEntity>>();

  WindowsManuallyClosedDirectoryWatcher(this.path) : _files = PathSet(path) {
    // Before we're ready to emit events, wait for [_listDir] to complete.
    _listDir().then((_) {
      _startWatch();
      _startParentWatcher();
      if (!isReady) {
        _readyCompleter.complete();
      }
    });
  }

  @override
  void close() {
    _watchSubscription?.cancel();
    _parentWatchSubscription?.cancel();
    _initialListSubscription?.cancel();
    for (var sub in _listSubscriptions) {
      sub.cancel();
    }
    _listSubscriptions.clear();
    for (var pendingPoll in _pendingPolls.values) {
      pendingPoll.cancelTimer();
    }
    _pendingPolls.clear();
    _watchSubscription = null;
    _parentWatchSubscription = null;
    _initialListSubscription = null;
    _eventsController.close();
  }

  /// On Windows, if [directory] is deleted, we will not receive any event.
  ///
  /// Instead, we add a watcher on the parent folder (if any), that can notify
  /// us about [path]. This also includes events such as moves.
  void _startParentWatcher() {
    var absoluteDir = p.absolute(path);
    var parent = p.dirname(absoluteDir);
    try {
      // Check if [path] is already the root directory.
      if (FileSystemEntity.identicalSync(parent, path)) return;
    } on FileSystemException catch (_) {
      // Either parent or path or both might be gone due to concurrently
      // occurring changes. Just ignore and continue. If we fail to
      // watch path we will report an error from _startWatch.
      return;
    }
    var parentStream = Directory(parent).watch(recursive: false);
    _parentWatchSubscription = parentStream.listen(
      (event) {
        // Only look at events for 'directory'.
        if (p.basename(event.path) != p.basename(absoluteDir)) return;
        // Test if the directory is removed. FileSystemEntity.typeSync will
        // return NOT_FOUND if it's unable to decide upon the type, including
        // access denied issues, which may happen when the directory is deleted.
        // FileSystemMoveEvent and FileSystemDeleteEvent events will always mean
        // the directory is now gone.
        if (event is FileSystemMoveEvent ||
            event is FileSystemDeleteEvent ||
            (FileSystemEntity.typeSync(path) ==
                FileSystemEntityType.notFound)) {
          for (var path in _files.paths) {
            _emitEvent(ChangeType.REMOVE, path);
          }
          _files.clear();
          close();
        }
      },
      onError: (error) {
        // Ignore errors, simply close the stream. The user listens on
        // [directory], and while it can fail to listen on the parent, we may
        // still be able to listen on the path requested.
        _parentWatchSubscription?.cancel();
        _parentWatchSubscription = null;
      },
    );
  }

  void _onEvent(FileSystemEvent fileSystemEvent) {
    assert(isReady);
    var event = Event.checkAndConvert(fileSystemEvent);
    if (event == null) return;

    _schedulePoll(event.path,
        created: event.type == EventType.createFile ||
            event.type == EventType.createDirectory,
        modified: event.type == EventType.modifyFile ||
            event.type == EventType.modifyDirectory,
        deleted: event.type == EventType.delete ||
            event.type == EventType.moveFile ||
            event.type == EventType.moveDirectory,
        movedOnto: false);
    final destination = event.destination;
    if (destination != null) {
      _schedulePoll(destination,
          created: false, modified: false, deleted: false, movedOnto: true);
    }
  }

  void _schedulePoll(String path,
      {required bool created,
      required bool modified,
      required bool deleted,
      required bool movedOnto}) {
    final pendingPoll =
        _pendingPolls.putIfAbsent(path, () => _PendingPoll(path));
    pendingPoll.startOrReset(() => _poll(pendingPoll),
        created: created,
        modified: modified,
        deleted: deleted,
        movedOnto: movedOnto);
  }

  /// Polls for the path specified by [poll] and emits events for any changes.
  void _poll(_PendingPoll poll) {
    final path = poll.path;
    final events = _eventsBasedOnFileSystem(path,
        reportCreate: poll.created || poll.movedOnto,
        reportDelete: poll.deleted,
        // A modification can be reported due to a modification event, a
        // create+delete together, or if the path is a move destination.
        // The important case where the file is present, an event arrives
        // for the file and a modification is _not_ reported is when the file
        // was already discovered by listing a new directory, then the "add"
        // event for it is processed afterwards.
        reportModification:
            poll.modified || (poll.created && poll.deleted) || poll.movedOnto);

    for (final event in events) {
      switch (event.type) {
        case EventType.createFile:
          _emitEvent(ChangeType.ADD, path);
          _files.add(path);

        case EventType.createDirectory:
          final stream =
              Directory(path).listRecursivelyIgnoringErrors(followLinks: false);
          final subscription = stream.listen((entity) {
            if (entity is Directory) return;
            if (_files.contains(entity.path)) return;

            _emitEvent(ChangeType.ADD, entity.path);
            _files.add(entity.path);
          }, cancelOnError: true);
          subscription.onDone(() {
            _listSubscriptions.remove(subscription);
          });
          subscription.onError((Object e, StackTrace stackTrace) {
            _listSubscriptions.remove(subscription);
            _emitError(e, stackTrace);
          });
          _listSubscriptions.add(subscription);

        case EventType.modifyFile:
          _emitEvent(ChangeType.MODIFY, path);

        case EventType.delete:
          for (final removedPath in _files.remove(path)) {
            _emitEvent(ChangeType.REMOVE, removedPath);
          }

        // Never returned by `_eventsBasedOnFileSystem`.
        case EventType.moveFile:
        case EventType.moveDirectory:
        case EventType.modifyDirectory:
          throw StateError(event.type.name);
      }
    }
  }

  /// Returns zero or more events that describe the change between the last
  /// known state of [path] and its current state on the filesystem.
  ///
  /// This returns a list whose order should be reflected in the events emitted
  /// to the user, unlike the batched events from [Directory.watch].
  ///
  ///
  /// [reportCreate], [reportModification] and [reportDelete] restrict the types
  /// of events that can be emitted.
  List<Event> _eventsBasedOnFileSystem(String path,
      {required bool reportCreate,
      required bool reportModification,
      required bool reportDelete}) {
    var fileExisted = _files.contains(path);
    var dirExisted = _files.containsDir(path);

    bool fileExists;
    bool dirExists;
    try {
      final type = FileSystemEntity.typeSync(path, followLinks: false);
      fileExists = type == FileSystemEntityType.file ||
          type == FileSystemEntityType.link;
      dirExists = type == FileSystemEntityType.directory;
    } on FileSystemException {
      return const <Event>[];
    }

    var events = <Event>[];
    if (fileExisted) {
      if (fileExists) {
        if (reportModification) events.add(Event.modifyFile(path));
      } else {
        if (reportDelete) events.add(Event.delete(path));
      }
    } else if (dirExisted) {
      if (dirExists) {
        // If we got contradictory events for a directory that used to exist and
        // still exists, we need to rescan the whole thing in case it was
        // replaced with a different directory.
        if (reportDelete) events.add(Event.delete(path));
        if (reportCreate) events.add(Event.createDirectory(path));
      } else {
        if (reportDelete) events.add(Event.delete(path));
      }
    }

    if (!fileExisted && fileExists) {
      if (reportCreate) events.add(Event.createFile(path));
    } else if (!dirExisted && dirExists) {
      if (reportCreate) events.add(Event.createDirectory(path));
    }

    return events;
  }

  /// The callback that's run when the [Directory.watch] stream is closed.
  /// Note that this is unlikely to happen on Windows, unless the system itself
  /// closes the handle.
  void _onDone() {
    _watchSubscription = null;

    // Emit remove events for any remaining files.
    for (var file in _files.paths) {
      _emitEvent(ChangeType.REMOVE, file);
    }
    _files.clear();
    close();
  }

  /// Start or restart the underlying [Directory.watch] stream.
  void _startWatch() {
    // Note: in older SDKs "watcher closed" exceptions might not get sent over
    // the stream returned by watch, and must be caught via a zone handler.
    runZonedGuarded(
      () {
        var innerStream = Directory(path).watch(recursive: true);
        _watchSubscription = innerStream.listen(
          _onEvent,
          onError: _restartWatchOnOverflowOr(_eventsController.addError),
          onDone: _onDone,
        );
      },
      _restartWatchOnOverflowOr(Error.throwWithStackTrace),
    );
  }

  void Function(Object, StackTrace) _restartWatchOnOverflowOr(
      void Function(Object, StackTrace) otherwise) {
    return (Object error, StackTrace stackTrace) async {
      if (error is FileSystemException &&
          error.message.startsWith('Directory watcher closed unexpectedly')) {
        // Wait to work around https://github.com/dart-lang/sdk/issues/61378.
        // Give the VM time to reset state after the error. See the issue for
        // more discussion of the workaround.
        await _watchSubscription?.cancel();
        await Future<void>.delayed(const Duration(milliseconds: 1));
        _eventsController.addError(error, stackTrace);
        _startWatch();
      } else {
        otherwise(error, stackTrace);
      }
    };
  }

  /// Starts or restarts listing the watched directory to get an initial picture
  /// of its state.
  Future<void> _listDir() {
    assert(!isReady);
    _initialListSubscription?.cancel();

    _files.clear();
    var completer = Completer<void>();
    var stream =
        Directory(path).listRecursivelyIgnoringErrors(followLinks: false);
    void handleEntity(FileSystemEntity entity) {
      if (entity is! Directory) _files.add(entity.path);
    }

    _initialListSubscription = stream.listen(
      handleEntity,
      onError: _emitError,
      onDone: completer.complete,
      cancelOnError: true,
    );
    return completer.future;
  }

  /// Emit an event with the given [type] and [path].
  void _emitEvent(ChangeType type, String path) {
    if (!isReady) return;

    _eventsController.add(WatchEvent(type, path));
  }

  /// Emit an error, then close the watcher.
  void _emitError(Object error, StackTrace stackTrace) {
    // Guarantee that ready always completes.
    if (!isReady) {
      _readyCompleter.complete();
    }
    _eventsController.addError(error, stackTrace);
    close();
  }
}

/// A pending poll of a path.
///
/// Holds the union of the types of events that were received for the path while
/// waiting to do the poll.
class _PendingPoll {
  // See _WindowsDirectoryWatcher class comment for why 5ms.
  static const Duration _batchDelay = Duration(milliseconds: 5);

  final String path;
  bool created = false;
  bool modified = false;
  bool deleted = false;
  bool movedOnto = false;

  Timer? timer;

  _PendingPoll(this.path);

  /// Starts or resets the poll timer.
  ///
  /// [function] will be called if the timer completes.
  ///
  /// ORs [created], [modified], [deleted] and [movedOnto] into the poll
  /// state.
  void startOrReset(void Function() function,
      {required bool created,
      required bool modified,
      required bool deleted,
      required bool movedOnto}) {
    this.created |= created;
    this.modified |= modified;
    this.deleted |= deleted;
    this.movedOnto |= movedOnto;
    timer?.cancel();
    timer = Timer(_batchDelay, function);
  }

  void cancelTimer() {
    timer?.cancel();
  }
}
