package server.logic.ws_protocol.JSON.messages;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;

final class ReadReceiptPayload {
    final String refToLogin;
    final String refFromLogin;
    final long refTimeMs;
    final long refNonce;
    final int refType;

    private ReadReceiptPayload(String refToLogin, String refFromLogin, long refTimeMs, long refNonce, int refType) {
        this.refToLogin = refToLogin;
        this.refFromLogin = refFromLogin;
        this.refTimeMs = refTimeMs;
        this.refNonce = refNonce;
        this.refType = refType;
    }

    static ReadReceiptPayload parse(byte[] payload) {
        if (payload == null || payload.length < 1 + 1 + 8 + 4 + 2) {
            throw new IllegalArgumentException("BAD_RECEIPT_PAYLOAD_LEN");
        }
        ByteBuffer bb = ByteBuffer.wrap(payload).order(ByteOrder.BIG_ENDIAN);
        String refTo = readAscii(bb, 1, 60, "BAD_RECEIPT_TO_LOGIN");
        String refFrom = readAscii(bb, 1, 60, "BAD_RECEIPT_FROM_LOGIN");
        long refTimeMs = bb.getLong();
        if (refTimeMs < 0) throw new IllegalArgumentException("BAD_RECEIPT_TIME");
        long refNonce = Integer.toUnsignedLong(bb.getInt());
        int refType = Short.toUnsignedInt(bb.getShort());
        if (refType < SignedMessageBlock.TYPE_INCOMING_TEXT || refType > SignedMessageBlock.TYPE_READ_OUTGOING_COPY) {
            throw new IllegalArgumentException("BAD_RECEIPT_REF_TYPE");
        }
        if (bb.hasRemaining()) {
            throw new IllegalArgumentException("BAD_RECEIPT_PAYLOAD_LEN");
        }
        return new ReadReceiptPayload(refTo, refFrom, refTimeMs, refNonce, refType);
    }

    String refBaseKey() {
        return SignedMessageKeys.baseKey(refToLogin, refFromLogin, refTimeMs, refNonce);
    }

    private static String readAscii(ByteBuffer bb, int minLen, int maxLen, String code) {
        if (!bb.hasRemaining()) throw new IllegalArgumentException(code);
        int len = Byte.toUnsignedInt(bb.get());
        if (len < minLen || len > maxLen || bb.remaining() < len) throw new IllegalArgumentException(code);
        byte[] bytes = new byte[len];
        bb.get(bytes);
        for (byte b : bytes) {
            if (b < 0x20 || b > 0x7E) throw new IllegalArgumentException(code);
        }
        return new String(bytes, StandardCharsets.US_ASCII);
    }
}
