I wrote it for you; it did not have thorough testing, but it appears to do what you seek.
The logic behind it is to loop over every single character in the text. If the character is equal to the character in downcase, append it to the return string in upcase. If not, append it in downcase. At the end, delete region and insert the return string.
It works immediate on a page of text, though I'd be wary to use it on huge texts (should be fine still).
(defun toggle-case ()
(interactive)
(when (region-active-p)
(let ((i 0)
(return-string "")
(input (buffer-substring-no-properties (region-beginning) (region-end))))
(while (< i (- (region-end) (region-beginning)))
(let ((current-char (substring input i (+ i 1))))
(if (string= (substring input i (+ i 1)) (downcase (substring input i (+ i 1))))
(setq return-string
(concat return-string (upcase (substring input i (+ i 1)))))
(setq return-string
(concat return-string (downcase (substring input i (+ i 1)))))))
(setq i (+ i 1)))
(delete-region (region-beginning) (region-end))
(insert return-string))))