package ch.polgrabia.demos.client;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.WebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;

public class ClientPeriodicStdinScannerParticle extends AbstractVerticle implements Handler<Long> {
  private static final Logger logger = LoggerFactory.getLogger(ClientPeriodicStdinScannerParticle.class);
  private final InputStream inputStream;
  private Buffer clientPayloadRemainderBuffer = Buffer.buffer();

  ClientPeriodicStdinScannerParticle(InputStream inputStream) {
    this.inputStream = inputStream;
  }

  private int newLineIndex(byte[] clientPayload, int prevIdx) {
    for (int i = prevIdx; i < clientPayload.length; i++) {
      if (clientPayload[i] == '\n' || clientPayload[i] == '\r') {
        return i;
      }
    }
    return -1;
  }

  @Override
  public void handle(Long event) {
    {
      // TODO this doesn't seem to be working on wsl environment. Needs to be resolved or changed how it
      //      fetches the input
      try {
        int available = inputStream.available();
        if (available > 0) {
          logger.debug("Got available: {}", available);
          clientPayloadRemainderBuffer.appendBytes(inputStream.readNBytes(available));
        }

        byte[] clientPayload = clientPayloadRemainderBuffer.getBytes();

        int idx, prevIdx = 0;
        do {
          idx = newLineIndex(clientPayload, prevIdx);
          if (idx >= 0) {
            // TODO here don't assume we deal with linux eol
            var eolLength =
              idx < clientPayload.length - 1
                && clientPayload[idx] == '\r'
                && clientPayload[idx + 1] == '\n'
                ? 2 : 1;
            int len = idx - prevIdx;
            Buffer b = Buffer.buffer(len);
            b = b.appendBytes(clientPayload, prevIdx, len);
            b = b.appendByte((byte) '\n');
            logger.info("Sending binary message: {}", b);
            getVertx()
              .eventBus()
              .publish(Constants.CLIENT_WEBSOCKET_SENDER_EVENTBUS_KEY, b);
            prevIdx = idx + eolLength;
          }
        } while (idx >= 0 && prevIdx < clientPayload.length);
        int remainderLength = clientPayload.length - prevIdx + 1;
        if (remainderLength > 0 && prevIdx < clientPayload.length) {
          clientPayloadRemainderBuffer = Buffer.buffer(remainderLength)
            .appendBytes(clientPayload, prevIdx, remainderLength);
        } else {
          clientPayloadRemainderBuffer = Buffer.buffer();
        }
      } catch (IOException e) {
        logger.error("Failed to read client input", e);
      }
    }
  }
}
