P2WPKH program is identified by an output containing 0{20-byte-public-key-hash}. The spending transaction witness must contain the proper key which hashes to the 20 byte hash specified in the output. This is different than the regular scriptPubKey format used so far (1976a914{pkh}88ac is not necessary anymore).
But, when we want to hash the P2WPKH transaction for signing, we suddenly prefix the 20 byte pkh from output with 19761914 and suffix it with 88ac. Why do we do this? Why not just use the 20 byte pkh? If we don't use the old srcriptPubKey format for redeeming transactions why do we use it in hashing?
The scriptCode is there for defining what is actually done in validation of the input. It is there to explicitly define what validation is happening. Since P2WPKH validation is basically the same as P2PKH, the P2PKH script is used as the scriptCode.
I keep seeing the main justification for SegWit being that it solved the sighash problem, where it ends with a hand-wave of "The signature script contains the secp256k1 signature, which cant sign itself"
Can someone explain to me why it can't sign itself? (preferably with an example)
A signature cannot sign itself because the signature does not exist to be signed until it is created. Signatures sign the hash of the message. The message is the unsigned transaction. Once the signature is created, if you were to include it in the message and sign it again, you would have a different signature. Having the signature in the message always changes the resulting signature so it can never sign itself.