// 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.
//
// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write
// OtherResources=certificates/server_chain.pem
// OtherResources=certificates/server_key.pem
// OtherResources=certificates/trusted_certs.pem

import "dart:async";
import "dart:io";

import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";

String localFile(path) => Platform.script.resolve(path).toFilePath();

SecurityContext serverContext = new SecurityContext()
  ..useCertificateChain(localFile('certificates/server_chain.pem'))
  ..usePrivateKey(localFile('certificates/server_key.pem'),
      password: 'dartdart');

SecurityContext clientContext = new SecurityContext()
  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));

late InternetAddress HOST;
Future<RawSecureServerSocket> startEchoServer() {
  return RawSecureServerSocket.bind(HOST, 0, serverContext).then((server) {
    server.listen((RawSecureSocket client) {
      List<List<int>> readChunks = <List<int>>[];
      List<int>? dataToWrite = null;
      int bytesWritten = 0;
      client.writeEventsEnabled = false;
      client.listen((event) {
        switch (event) {
          case RawSocketEvent.read:
            Expect.isTrue(bytesWritten == 0);
            Expect.isTrue(client.available() > 0);
            readChunks.add(client.read()!);
            break;
          case RawSocketEvent.write:
            Expect.isFalse(client.writeEventsEnabled);
            Expect.isNotNull(dataToWrite);
            bytesWritten += client.write(
                dataToWrite!, bytesWritten, dataToWrite!.length - bytesWritten);
            if (bytesWritten < dataToWrite!.length) {
              client.writeEventsEnabled = true;
            }
            if (bytesWritten == dataToWrite!.length) {
              client.shutdown(SocketDirection.send);
            }
            break;
          case RawSocketEvent.readClosed:
            dataToWrite = readChunks.fold<List<int>>(<int>[], (list, x) {
              list.addAll(x);
              return list;
            });
            client.writeEventsEnabled = true;
            break;
        }
      });
    });
    return server;
  });
}

Future testClient(server) {
  Completer success = new Completer();
  List<String> chunks = <String>[];
  SecureSocket.connect(HOST, server.port, context: clientContext)
      .then((socket) {
    socket.write("Hello server.");
    socket.close();
    socket.listen((List<int> data) {
      var received = new String.fromCharCodes(data);
      chunks.add(received);
    }, onDone: () {
      String reply = chunks.join();
      Expect.equals("Hello server.", reply);
      success.complete(server);
    });
  });
  return success.future;
}

void main() {
  asyncStart();
  InternetAddress.lookup("localhost")
      .then((hosts) => HOST = hosts.first)
      .then((_) => startEchoServer())
      .then(testClient)
      .then((server) => server.close())
      .then((_) => asyncEnd());
}
