package ch.polgrabia.demos;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;

public class PingPongHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(PingPongHandler.class);
    public static final int ONE_READ_SIZE = 0x1000;

    private final byte[] preamble = "Got request:%s"
            .formatted(System.lineSeparator())
            .getBytes(StandardCharsets.UTF_8);
    private final byte[] payloadSeparator = "--------------------%s"
            .formatted(System.lineSeparator())
            .getBytes(StandardCharsets.UTF_8);

    private final byte[] quiteCommand = "quit".getBytes(StandardCharsets.UTF_8);
    private final byte[] quittingMessage = "Quitting...".getBytes(StandardCharsets.UTF_8);

    private final byte[] inputLine = new byte[ONE_READ_SIZE];

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        var preambleBuffer = ctx.alloc().buffer(preamble.length);
        ByteBuf separatorBuffer;
        ByteBuf newlinesBuffer;
        ByteBuf responseBuffer;

        preambleBuffer.writeBytes(preamble);
        ctx.write(preambleBuffer);

        separatorBuffer = ctx.alloc().buffer(payloadSeparator.length);
        separatorBuffer.writeBytes(payloadSeparator);
        ctx.write(separatorBuffer);

        var bbmsg = (ByteBuf) msg;

        int read = 0;
        while (bbmsg.isReadable()) {
            int avail = bbmsg.readableBytes();
            bbmsg.readBytes(inputLine,0, Math.min(avail, inputLine.length));

            if (read == 0 && checkIfSubseqAtOffset(inputLine, quiteCommand)) {
                responseBuffer = ctx.alloc().buffer(quittingMessage.length);
                responseBuffer.writeBytes(quittingMessage);
                ctx.flush();
                ctx.close();
                return;
            }

            int n = Math.min(avail, ONE_READ_SIZE);
            read += n;
            responseBuffer = ctx.alloc().buffer(n);
            responseBuffer.writeBytes(inputLine, 0, n);
            ctx.write(responseBuffer);
        }


        separatorBuffer = ctx.alloc().buffer(payloadSeparator.length);
        separatorBuffer.writeBytes(payloadSeparator);
        ctx.write(separatorBuffer);

        newlinesBuffer = ctx.alloc().buffer(System.lineSeparator().getBytes(StandardCharsets.UTF_8).length * 2);
        newlinesBuffer.writeBytes(System.lineSeparator().getBytes(StandardCharsets.UTF_8));
        newlinesBuffer.writeBytes(System.lineSeparator().getBytes(StandardCharsets.UTF_8));
        ctx.write(newlinesBuffer);

        ctx.flush();
    }

    private boolean checkIfSubseqAtOffset(byte[] seq, byte[] subseq) {
        if (seq.length < subseq.length) {
            return false;
        }

        for (int i = 0; i < subseq.length; i++) {
            if (seq[i] != subseq[i]) {
                return false;
            }
        }

        return true;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("Got exception", cause);
        ctx.close();
    }
}
