This works for all 3 of your cases for me:
if @% == ""
" No filename for current buffer
elseif filereadable(@%) == 0
" File doesn't exist yet
elseif line('$') == 1 && col('$') == 1
" File is empty
au VimEnter * call InsertIfEmpty()
These could probably be condensed into just the last check for a file being empty, since no filename or a file that doesn't exist typically start as empty buffers. However, it is probably possible that some other plugin pre-fills some stuff in one of the first two cases (like some template plugins), so it is best to check all three.
The first test you already had.
The second test needs to check
filereadable against the value of zero (doesn't exist) to decide if it is new (opposite of what you had).
The last test checks that the number of the last line in the file is 1 (which is also the first line, meaning that there is only one line), and that the column number of the end of line (column after the last character in the line) is 1, which would mean there are 0 characters. If there is only 1 line with 0 characters in it, then the file must be empty.
One final note: The way you have your statements in the question can result in some surprising results. Namely, you are setting
BufNewFile only if conditions are met at startup, but then those autocommands exist for the rest of your session. So, if you were to start on an empty file, which sets these commands, every subsequent file opened (new or not, empty or not) would start in insert mode.
VimEnter is run at the end of Vim's startup and only once for the whole session. This way, your tests only run when you start Vim and not any other time.