// 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.

@TestOn('vm')

import 'dart:io';

import 'package:stream_channel/stream_channel.dart';
import 'package:test/test.dart';

import 'package:web_socket_channel/web_socket_channel.dart';

void main() {
  group("using WebSocketChannel", () {
    test("a client can communicate with a WebSocket server", () async {
      var server = await HttpServer.bind("localhost", 0);
      server.transform(new WebSocketTransformer()).listen((webSocket) {
        webSocket.add("hello!");
        webSocket.listen((request) {
          expect(request, equals("ping"));
          webSocket.add("pong");
          webSocket.close();
        });
      });

      var client = new HttpClient();
      var request = await client.openUrl(
          "GET", Uri.parse("http://localhost:${server.port}"));
      request.headers
        ..set("Connection", "Upgrade")
        ..set("Upgrade", "websocket")
        ..set("Sec-WebSocket-Key", "x3JJHMbDL1EzLkh9GBhXDw==")
        ..set("Sec-WebSocket-Version", "13");

      var response = await request.close();
      var socket = await response.detachSocket();
      var innerChannel = new StreamChannel<List<int>>(socket, socket);
      var webSocket = new WebSocketChannel(innerChannel, serverSide: false);

      var n = 0;
      await webSocket.stream.listen((message) {
        if (n == 0) {
          expect(message, equals("hello!"));
          webSocket.sink.add("ping");
        } else if (n == 1) {
          expect(message, equals("pong"));
          webSocket.sink.close();
          server.close();
        } else {
          fail("Only expected two messages.");
        }
        n++;
      }).asFuture();
    });

    test("a server can communicate with a WebSocket client", () async {
      var server = await HttpServer.bind("localhost", 0);
      server.listen((request) async {
        var response = request.response;
        response.statusCode = 101;
        response.headers
          ..set("Connection", "Upgrade")
          ..set("Upgrade", "websocket")
          ..set(
              "Sec-WebSocket-Accept",
              WebSocketChannel.signKey(
                  request.headers.value('Sec-WebSocket-Key')));
        response.contentLength = 0;

        var socket = await response.detachSocket();
        var innerChannel = new StreamChannel<List<int>>(socket, socket);
        var webSocket = new WebSocketChannel(innerChannel);
        webSocket.sink.add("hello!");

        var message = await webSocket.stream.first;
        expect(message, equals("ping"));
        webSocket.sink.add("pong");
        webSocket.sink.close();
      });

      var webSocket = await WebSocket.connect('ws://localhost:${server.port}');
      var n = 0;
      await webSocket.listen((message) {
        if (n == 0) {
          expect(message, equals("hello!"));
          webSocket.add("ping");
        } else if (n == 1) {
          expect(message, equals("pong"));
          webSocket.close();
          server.close();
        } else {
          fail("Only expected two messages.");
        }
        n++;
      }).asFuture();
    });
  });
}
