How to set up a command-based communication using I2C

...or some other event. After the callback function returns the caller can do everything, e.g. flush remaining bytes in the input buffer.

I don't think so. Wire.available() can work as documented only with an input buffer.

On a 32 bit machine all multi-byte variables should be aligned to their natural boundaries. It will cost some time to access a long variable not aligned to a 32 bit boundary. Also packing a 32 bit byte type into 24 bits is at least questionable. Did you check the struct size and compiler warnings?