// Copyright (c) 2017, 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.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:analysis_server_client/listener/server_listener.dart';
import 'package:analysis_server_client/protocol.dart';
import 'package:analysis_server_client/server.dart';
import 'package:test/test.dart';

void main() {
  late _ServerListener listener;
  late MockProcess process;
  late Server server;

  setUp(() async {
    process = MockProcess();
    listener = _ServerListener();
    server = Server(process: process, listener: listener);
  });

  group('listenToOutput', () {
    test('good', () async {
      process.stdout = _goodMessage();
      process.stderr = _noMessage();

      final future = server.send('blahMethod', null);
      server.listenToOutput();

      final response = (await future)!;
      expect(response['foo'], 'bar');
    });

    test('error', () async {
      process.stdout = _badMessage();
      process.stderr = _noMessage();

      final future = server.send('blahMethod', null);
      // ignore: unawaited_futures
      future.catchError((e) {
        expect(e, const TypeMatcher<RequestError>());
        final error = e as RequestError;
        expect(error.code, RequestErrorCode.UNKNOWN_REQUEST);
        expect(error.message, 'something went wrong');
        expect(error.stackTrace, 'some long stack trace');
        return <String, Object?>{};
      });
      server.listenToOutput();
    });

    test('event', () async {
      process.stdout = _eventMessage();
      process.stderr = _noMessage();

      final completer = Completer();
      void eventHandler(Notification notification) {
        expect(notification.event, 'fooEvent');
        var params = notification.params!;
        expect(params.length, 2);
        expect(params['foo'] as String, 'bar');
        expect(params['baz'] as String, 'bang');
        completer.complete();
      }

      // ignore: unawaited_futures
      server.send('blahMethod', null);
      server.listenToOutput(notificationProcessor: eventHandler);
      await completer.future;
    });

    test('unexpected message', () async {
      // No 'id', so not a response.
      // No 'event', so not a notification.
      process.stdout = Stream.value(utf8.encode(json.encode({'foo': 'bar'})));
      process.stderr = _noMessage();

      server.listenToOutput();

      // Must happen for the test to pass.
      await listener.unexpectedMessageController.stream.first;
    });

    test('unexpected notification format', () async {
      process.stdout = Stream.value(
        utf8.encode(json.encode({'event': 'foo', 'noParams': '42'})),
      );
      process.stderr = _noMessage();

      server.listenToOutput();

      // Must happen for the test to pass.
      await listener.unexpectedNotificationFormatCompleter.stream.first;
    });

    test('unexpected response', () async {
      // We have no asked anything, but got a response.
      process.stdout = Stream.value(utf8.encode(json.encode({'id': '0'})));
      process.stderr = _noMessage();

      server.listenToOutput();

      // Must happen for the test to pass.
      await listener.unexpectedResponseCompleter.stream.first;
    });

    test('unexpected response format', () async {
      // We expect that the first request has id `0`.
      // The response is invalid - the "result" field is not an object.
      process.stdout = Stream.value(
        utf8.encode(json.encode({'id': '0', 'result': '42'})),
      );
      process.stderr = _noMessage();

      // ignore: unawaited_futures
      server.send('blahMethod', null);
      server.listenToOutput();

      // Must happen for the test to pass.
      await listener.unexpectedResponseFormatCompleter.stream.first;
    });
  });

  group('stop', () {
    test('ok', () async {
      final mockout = StreamController<List<int>>();
      process.stdout = mockout.stream;
      process.stderr = _noMessage();
      // ignore: unawaited_futures
      process.mockin.controller.stream.first.then((_) {
        var encoded = json.encode({'id': '0'});
        mockout.add(utf8.encode('$encoded\n'));
      });
      process.exitCode = Future.value(0);

      server.listenToOutput();
      await server.stop(timeLimit: const Duration(milliseconds: 1));
      expect(process.killed, isFalse);
    });
    test('stopped', () async {
      final mockout = StreamController<List<int>>();
      process.stdout = mockout.stream;
      process.stderr = _noMessage();
      process.exitCode = Future.value(0);

      server.listenToOutput();
      await server.stop(timeLimit: const Duration(milliseconds: 1));
      expect(process.killed, isFalse);
    });
    test('kill', () async {
      final mockout = StreamController<List<int>>();
      process.stdout = mockout.stream;
      process.stderr = _noMessage();
      process.exitCode = Future.delayed(const Duration(seconds: 1), () => 0);

      server.listenToOutput();
      await server.stop(timeLimit: const Duration(milliseconds: 10));
      expect(process.killed, isTrue);
    });
  });
}

final _badErrorMessage = {
  'code': 'UNKNOWN_REQUEST',
  'message': 'something went wrong',
  'stackTrace': 'some long stack trace',
};

Stream<List<int>> _badMessage() async* {
  yield utf8.encode('The Dart VM service is listening on foo bar\n');
  final sampleJson = {'id': '0', 'error': _badErrorMessage};
  yield utf8.encode(json.encode(sampleJson));
}

Stream<List<int>> _eventMessage() async* {
  yield utf8.encode('The Dart VM service is listening on foo bar\n');
  final sampleJson = {
    'event': 'fooEvent',
    'params': {'foo': 'bar', 'baz': 'bang'},
  };
  yield utf8.encode(json.encode(sampleJson));
}

Stream<List<int>> _goodMessage() async* {
  yield utf8.encode('The Dart VM service is listening on foo bar\n');
  final sampleJson = {
    'id': '0',
    'result': {'foo': 'bar'},
  };
  yield utf8.encode(json.encode(sampleJson));
}

Stream<List<int>> _noMessage() async* {
  yield utf8.encode('');
}

class MockProcess implements Process {
  MockStdin mockin = MockStdin();

  bool killed = false;

  @override
  late Stream<List<int>> stderr;

  @override
  late Stream<List<int>> stdout;

  @override
  late Future<int> exitCode;

  @override
  IOSink get stdin => mockin;

  @override
  bool kill([ProcessSignal signal = ProcessSignal.sigterm]) {
    var wasKilled = killed;
    killed = true;
    return !wasKilled;
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

class MockStdin implements IOSink {
  final controller = StreamController<String>();

  @override
  void add(List<int> data) {
    controller.add(utf8.decode(data));
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

class _ServerListener with ServerListener {
  final unexpectedMessageController = StreamController<Object>();
  final unexpectedNotificationFormatCompleter = StreamController<Object>();
  final unexpectedResponseCompleter = StreamController<Object>();
  final unexpectedResponseFormatCompleter = StreamController<Object>();

  @override
  void log(String prefix, String details) {}

  @override
  void unexpectedMessage(Map<String, Object?> message) {
    unexpectedMessageController.add(message);
  }

  @override
  void unexpectedNotificationFormat(Map<String, Object?> message) {
    unexpectedNotificationFormatCompleter.add(message);
  }

  @override
  void unexpectedResponse(Map<String, Object?> message, Object id) {
    unexpectedResponseCompleter.add(message);
  }

  @override
  void unexpectedResponseFormat(Map<String, Object?> message) {
    unexpectedResponseFormatCompleter.add(message);
  }
}
