import "dart:async";
import 'dart:math';

import "./base.dart";

abstract class Service {
  String name;
  ServiceProvider provider;

  Service(this.provider, this.name) {
    provider._services[name] = this;
  }
}

class ServiceProvider {
  final Map<String, Service> _services = {};
  final Map<String, Completer<dynamic>> _requests = {};

  StreamController<Map<String, dynamic>> output = StreamController();
  late StreamSubscription s;

  ServiceProvider(Stream<Map<String, dynamic>> input) {
    s = input.listen(onMessage);
  }

  void onMessage(Map<String, dynamic> msg) {
    // print("Working on message");
    if (msg.containsKey("method")) {
      if (msg.containsKey("id")) {
        print("Message is request");
        // Request, not supported!
        return;
      } else {
        // print("Message is notification");
        // Notification
        // TODO: Implement
      }
    } else {
      // print("Message is response");
      // Response
      var req = _requests[msg["id"]];

      if (req == null) {
        // print("Could not find related request. Ignoring");
        return; // Irrelevant response
      }
      if (msg.containsKey("error")) {
        //TODO:
        req.completeError(JRPCError(msg["error"]["message"]));
      } else {
        req.complete(msg["result"]);
      }
    }
  }

  Future<dynamic> sendRequest(String method, dynamic params) {
    var id = nanoid(10);
    var req = {"jsonrpc": "2.0", "id": id, "method": method, "params": params};

    var completer = Completer<dynamic>();

    output.add(req);
    _requests[id] = completer;

    return completer.future;
  }

  void sendNotification(String method, dynamic params) {
    var req = {"jsonrpc": "2.0", "method": method, "params": params};
    output.add(req);
  }
}

// Copied from: https://github.com/pd4d10/nanoid-dart (MIT License)
final _random = Random.secure();
const urlAlphabet =
    'ModuleSymbhasOwnPr-0123456789ABCDEFGHNRVfgctiUvz_KqYTJkLxpZXIjQW';

String nanoid([int size = 21]) {
  final len = urlAlphabet.length;
  String id = '';
  while (0 < size--) {
    id += urlAlphabet[_random.nextInt(len)];
  }
  return id;
}
