package blockchain;

import blockchain.body.*;

/**
 * Parser for body record by header type/subType/version.
 */
public final class BodyRecordParser {

    private BodyRecordParser() {}

    public static BodyRecord parse(short type, short subType, short version, byte[] bodyBytes) {
        if (bodyBytes == null) throw new IllegalArgumentException("bodyBytes == null");

        int t = type & 0xFFFF;
        int v = version & 0xFFFF;
        int st = subType & 0xFFFF;

        // TECH supports Header v1 and CreateChannel current format (ver=1).
        if (t == (CreateChannelBody.TYPE & 0xFFFF)) {
            if (st == (HeaderBody.SUBTYPE_COMPAT & 0xFFFF) && v == (HeaderBody.VER & 0xFFFF)) {
                return new HeaderBody(subType, version, bodyBytes).check();
            }
            if (st == (CreateChannelBody.SUBTYPE & 0xFFFF)
                    && (v == (CreateChannelBody.VER & 0xFFFF))) {
                return new CreateChannelBody(subType, version, bodyBytes).check();
            }
            throw new IllegalArgumentException(
                    String.format("Unknown TECH body type/version/subType: type=%d ver=%d subType=%d", t, v, st)
            );
        }

        int key = (t << 16) | v;

        BodyRecord r = switch (key) {
            case TextBody.KEY -> {
                if (st == (MsgSubType.TEXT_POST & 0xFFFF)
                        || st == (MsgSubType.TEXT_EDIT_POST & 0xFFFF)
                        || st == (MsgSubType.TEXT_REPOST & 0xFFFF)) {
                    yield new TextLineBody(subType, version, bodyBytes);
                }

                if (st == (MsgSubType.TEXT_REPLY & 0xFFFF)
                        || st == (MsgSubType.TEXT_EDIT_REPLY & 0xFFFF)) {
                    yield new TextReplyBody(subType, version, bodyBytes);
                }

                throw new IllegalArgumentException("Unknown TEXT subType for type=1 ver=1: subType=" + st);
            }

            case ReactionBody.KEY -> new ReactionBody(subType, version, bodyBytes);
            case ConnectionBody.KEY -> new ConnectionBody(subType, version, bodyBytes);
            case UserParamBody.KEY -> new UserParamBody(subType, version, bodyBytes);

            default -> throw new IllegalArgumentException(String.format(
                    "Unknown body type/version from header: type=%d ver=%d subType=%d",
                    t, v, st
            ));
        };

        return r.check();
    }
}
