// Copyright 2021 The Fuchsia 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:convert' show utf8;

import 'package:fidl/fidl.dart';
import 'package:fidl_fuchsia_io/fidl_async.dart';
import 'package:fuchsia_vfs/vfs.dart';
import 'package:test/test.dart';
import 'package:zircon/zircon.dart';

void main() {
  group('remote dir: ', () {
    late PseudoDir _externalDirectory;
    late PseudoDir _localDirectory;
    late Channel _remoteDirHandle;

    setUp(() {
      final channelPair = ChannelPair();
      _externalDirectory = PseudoDir()
        ..addNode('file1.txt', PseudoFile.readOnlyStr(() => 'foo'))
        ..addNode(
            'bar',
            PseudoDir()
              ..addNode('file2.txt', PseudoFile.readOnlyStr(() => 'bar')))
        ..serve(InterfaceRequest<Node>(channelPair.first!));

      _remoteDirHandle = channelPair.second!;

      _localDirectory = PseudoDir();
    });

    tearDown(() {
      _externalDirectory.close();
      _localDirectory.close();
    });

    test('inode number', () {
      final dir = RemoteDir(_remoteDirHandle);
      expect(dir.inodeNumber(), inoUnknown);
    });

    test('type', () {
      final dir = RemoteDir(_remoteDirHandle);
      expect(dir.type(), DirentType.directory);
    });

    test('add remote after serve', () async {
      final proxy = _serveLocal(_localDirectory);
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));

      final contents =
          await _readFileContentsInRemoteDir(proxy, 'subdir', 'file1.txt');
      expect(contents, 'foo');

      proxy.ctrl.close();
    });

    test('add remote before serve', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
      final proxy = _serveLocal(_localDirectory);

      final contents =
          await _readFileContentsInRemoteDir(proxy, 'subdir', 'file1.txt');
      expect(contents, 'foo');

      proxy.ctrl.close();
    });

    test('can open with trailing slash', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
      final proxy = _serveLocal(_localDirectory);

      final contents =
          await _readFileContentsInRemoteDir(proxy, 'subdir/', 'file1.txt');
      expect(contents, 'foo');

      proxy.ctrl.close();
    });

    test('can open subdir of remote', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
      final proxy = _serveLocal(_localDirectory);

      final contents =
          await _readFileContentsInRemoteDir(proxy, 'subdir', 'bar/file2.txt');
      expect(contents, 'bar');

      proxy.ctrl.close();
    });

    test('can open file when remote is not at root', () async {
      _localDirectory.addNode(
          'dir1', PseudoDir()..addNode('dir2', RemoteDir(_remoteDirHandle)));

      final proxy = _serveLocal(_localDirectory);

      final contents =
          await _readFileContentsInRemoteDir(proxy, 'dir1/dir2', 'file1.txt');
      expect(contents, 'foo');

      proxy.ctrl.close();
    });

    test('can open nested file when remote is not at root', () async {
      _localDirectory.addNode(
          'dir1', PseudoDir()..addNode('dir2', RemoteDir(_remoteDirHandle)));

      final proxy = _serveLocal(_localDirectory);

      final contents = await _readFileContentsInRemoteDir(
          proxy, 'dir1/dir2', 'bar/file2.txt');
      expect(contents, 'bar');

      proxy.ctrl.close();
    });

    test('Can open paths through the remote dir', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));

      final proxy = _serveLocal(_localDirectory);

      expect(await _readFileContents(proxy, 'subdir/bar/file2.txt'), 'bar');
      expect(await _readFileContents(proxy, 'subdir/file1.txt'), 'foo');
      expect(await _readFileContents(proxy, 'subdir/./file1.txt'), 'foo');

      proxy.ctrl.close();
    });

    test('open with invalid flags', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
      final dir = _serveLocal(_localDirectory);

      // flags and statuses need to be kept in sync
      final flags = [OpenFlags.notDirectory];
      final statuses = [ZX.ERR_NOT_SUPPORTED];
      expect(flags.length, statuses.length);

      for (int i = 0; i < flags.length; i++) {
        DirectoryProxy proxy = DirectoryProxy();
        await dir.open(OpenFlags.describe | flags[i], 0, 'subdir',
            InterfaceRequest(proxy.ctrl.request().passChannel()));

        await proxy.onOpen.first.then((response) {
          expect(response.s, statuses[i]);
        }).catchError((err) async {
          fail(err.toString());
        });

        proxy.ctrl.close();
      }

      dir.ctrl.close();
    });

    test('connect with invalid flags', () async {
      final dir = RemoteDir(_remoteDirHandle);

      // flags and statuses need to be kept in sync
      final flags = [OpenFlags.notDirectory];
      final statuses = [ZX.ERR_NOT_SUPPORTED];
      expect(flags.length, statuses.length);

      for (int i = 0; i < flags.length; i++) {
        DirectoryProxy proxy = DirectoryProxy();
        dir.connect(OpenFlags.describe | flags[i], 0,
            InterfaceRequest(proxy.ctrl.request().passChannel()));

        await proxy.onOpen.first.then((response) {
          expect(response.s, statuses[i]);
        }).catchError((err) async {
          fail(err.toString());
        });
        proxy.ctrl.close();
      }

      dir.close();
    });

    test('open after close fails', () async {
      _localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle)..close());
      final dir = _serveLocal(_localDirectory);

      DirectoryProxy proxy = DirectoryProxy();
      await dir.open(OpenFlags.describe, 0, 'subdir',
          InterfaceRequest(proxy.ctrl.request().passChannel()));

      await proxy.onOpen.first.then((response) {
        expect(response.s, ZX.ERR_NOT_SUPPORTED);
      }).catchError((err) async {
        fail(err.toString());
      });

      proxy.ctrl.close();
      dir.ctrl.close();
    });

    test('connect after close failse', () async {
      final dir = RemoteDir(_remoteDirHandle)..close();

      DirectoryProxy proxy = DirectoryProxy();
      dir.connect(OpenFlags.describe, 0,
          InterfaceRequest(proxy.ctrl.request().passChannel()));

      await proxy.onOpen.first.then((response) {
        expect(response.s, ZX.ERR_NOT_SUPPORTED);
      }).catchError((err) async {
        fail(err.toString());
      });
      proxy.ctrl.close();
    });
  });
}

DirectoryProxy _serveLocal(PseudoDir dir) {
  DirectoryProxy proxy = DirectoryProxy();
  var status = dir.connect(OpenFlags.rightReadable | OpenFlags.rightWritable, 0,
      InterfaceRequest(proxy.ctrl.request().passChannel()));
  expect(status, ZX.OK);
  return proxy;
}

Future<DirectoryProxy> _openDirectory(DirectoryProxy dir, String path,
    [flags = OpenFlags.rightReadable]) async {
  DirectoryProxy proxy = DirectoryProxy();
  await dir.open(
      flags, 0, path, InterfaceRequest(proxy.ctrl.request().passChannel()));
  return proxy;
}

Future<String> _readFileContents(DirectoryProxy dir, String filename) async {
  final proxy = FileProxy();
  await dir.open(OpenFlags.rightReadable, modeTypeFile, filename,
      InterfaceRequest<Node>(proxy.ctrl.request().passChannel()));

  final data = await proxy.read(maxBuf);
  proxy.ctrl.close();
  return utf8.decode(data);
}

Future<String> _readFileContentsInRemoteDir(
    DirectoryProxy dir, String subdir, String filename) async {
  final proxy = await _openDirectory(dir, subdir);
  final contents = await _readFileContents(proxy, filename);
  proxy.ctrl.close();
  return contents;
}
