There is nothing largely complex about GameMode and GameState. At their core they are just two Actors. GameMode is not replicated because it's server only. GameState is replicated. GameMode does logic handling and stores said "state" on the GameState, where it can be replicated to clients.
Unreal was created on the premise of being an FPS engine. GameMode was designed to handle the game's mode's specific stuff. It would tick up points gained in capture point modes, track kills for elimination modes, track scores and respawn both teams when one team scores a point for team elems, etc.
And while game mode was handling all of that actual logic, it was storing it's states, like current kill counts, current team wins, current capture point progress all on GameState where even clients had access to it.
You're very free not to use these systems as well, they were just designed as an anti cheat ideology to keep game code cleaner because the only actor in the game that determined victory conditions was the GameMode and it only ever existed on the server.
Later on the GameMode became a basic way to store some default classes for a map. An easy way to change out AHUD actors, or use a different PlayerController. These being for games that have vastly differing modes like a game with combat maps and then a strategy mode maybe.
These days with Lyra the Experience system has taken over handling the default classes and extended on it heavily. GameMode can still do it's core job of determining game progress, and GameState can still stores game progress. Except they now do it via dynamic components. Instead of having "GameMode_CapturePoints", "GameMode_Elemination", Lyra just dynamically puts a single TeamDeathMatchScoring component on their GameState that handles the game's scoring and victory flow.