package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/ecdsa"
	"fmt"
	"log"

	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
)

func main() {
	// generate a random private key
	privateKey, err := crypto.GenerateKey()
	if err != nil {
		log.Fatal(err)
	}

	// private key convert to bytes
	privateKeyBytes := crypto.FromECDSA(privateKey)
	// fmt.Println(hexutil.Encode(privateKeyBytes)[2:]) // d593ae0363f9e66fe42a91fe0260067439e0760a3f4f554696cd9350c41ae7a6

	// private key to public key
	publicKey := privateKey.Public()

	// public key to hex
	// slice the 0x and the first 2 character 04 which is always the EC prefix and not required
	// interface typecast
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
	}
	publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
	// fmt.Println(hexutil.Encode(publicKeyBytes)[4:]) // b00316b00f432d90c1a3b5ee0f0fc4416c5aab07677edcc0ca65c53eb100f92fbde998d466bf7676cb4eaa2bf78f1a1df086718d54170e47b6d59315002d61df

	// generate public address from public key
	address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
	// fmt.Println(address) // 0x2Fc75Ce9cE3529758b5787ADE183566F765De0b9

	// to hex
	// TODO (?)
	// hash := sha3.NewLegacyKeccak256()
	// hash.Write(publicKeyBytes[1:])
	// fmt.Println(hexutil.Encode(hash.Sum(nil)[12:])) // 0x2fc75ce9ce3529758b5787ade183566f765de0b9

	encrypt(string(hexutil.Encode(privateKeyBytes)[2:]))
	fmt.Println("public", hexutil.Encode(publicKeyBytes)[4:])

	fmt.Println("address", address)

}

func encrypt(msg string) {

	key := []byte("wubanaistrong2024051132bitlength") // 32 bytes key for AES-256
	//plaintext := []byte("Hello, WorldHello, WorldHello, WorldHello, WorldHello, WorldHello, WorldHello, World!")

	plaintext := []byte(msg)

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	ciphertext := make([]byte, len(plaintext))
	stream := cipher.NewCTR(block, make([]byte, block.BlockSize()))
	stream.XORKeyStream(ciphertext, plaintext)

	//fmt.Printf("Encrypted private key: %s\n", base64.StdEncoding.EncodeToString(ciphertext))
	fmt.Printf("Encrypted private key: %x\n", ciphertext)

	decrypted := make([]byte, len(ciphertext))
	stream = cipher.NewCTR(block, make([]byte, block.BlockSize()))
	stream.XORKeyStream(decrypted, ciphertext)

	fmt.Printf("Decrypted: %s\n", decrypted)
}

// package main

// import (
// 	"crypto/rand"
// 	"crypto/rsa"
// 	"crypto/sha256"
// 	"crypto/x509"
// 	"encoding/base64"
// 	"encoding/pem"
// 	"fmt"

// 	"golang.org/x/crypto/ssh"
// )

// func marshalRSAPrivate(priv *rsa.PrivateKey) string {
// 	return string(pem.EncodeToMemory(&pem.Block{
// 		Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv),
// 	}))
// }

// func generateKey() (string, string, error) {
// 	reader := rand.Reader
// 	bitSize := 2048

// 	key, err := rsa.GenerateKey(reader, bitSize)
// 	if err != nil {
// 		return "", "", err
// 	}

// 	pub, err := ssh.NewPublicKey(key.Public())
// 	if err != nil {
// 		return "", "", err
// 	}
// 	pubKeyStr := string(ssh.MarshalAuthorizedKey(pub))
// 	privKeyStr := marshalRSAPrivate(key)

// 	return pubKeyStr, privKeyStr, nil
// }

// func encrypt(msg, publicKey string) (string, error) {
// 	parsed, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey))
// 	if err != nil {
// 		return "", err
// 	}
// 	// To get back to an *rsa.PublicKey, we need to first upgrade to the
// 	// ssh.CryptoPublicKey interface
// 	parsedCryptoKey := parsed.(ssh.CryptoPublicKey)

// 	// Then, we can call CryptoPublicKey() to get the actual crypto.PublicKey
// 	pubCrypto := parsedCryptoKey.CryptoPublicKey()

// 	// Finally, we can convert back to an *rsa.PublicKey
// 	pub := pubCrypto.(*rsa.PublicKey)

// 	encryptedBytes, err := rsa.EncryptOAEP(
// 		sha256.New(),
// 		rand.Reader,
// 		pub,
// 		[]byte(msg),
// 		nil)
// 	if err != nil {
// 		return "", err
// 	}
// 	return base64.StdEncoding.EncodeToString(encryptedBytes), nil
// }

// func decrypt(data, priv string) (string, error) {
// 	data2, err := base64.StdEncoding.DecodeString(data)
// 	if err != nil {
// 		return "", err
// 	}

// 	block, _ := pem.Decode([]byte(priv))
// 	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
// 	if err != nil {
// 		return "", err
// 	}

// 	decrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, key, data2, nil)
// 	if err != nil {
// 		return "", err
// 	}
// 	return string(decrypted), nil
// }

// func main() {
// 	pubKey, privKey, _ := generateKey()
// 	fmt.Println("my public key is...")
// 	fmt.Println(pubKey)
// 	fmt.Println("my private key is...")
// 	fmt.Println(privKey)

// 	encryptedData, _ := encrypt("hello world", pubKey)
// 	fmt.Println("my encrypted message is...")
// 	fmt.Println(encryptedData)
// 	fmt.Println("")

// 	decryptedData, _ := decrypt(encryptedData, privKey)
// 	fmt.Println("and the decrypted message is...")
// 	fmt.Println(decryptedData)
// }

// package main

// import (
// 	"crypto/aes"
// 	"crypto/cipher"
// 	"encoding/base64"
// 	"fmt"

// 	"github.com/tyler-smith/go-bip32"
// 	"github.com/tyler-smith/go-bip39"
// )

// func main() {

// 	// Generate a mnemonic for memorization or user-friendly seeds
// 	entropy, _ := bip39.NewEntropy(256)
// 	mnemonic, _ := bip39.NewMnemonic(entropy)

// 	// Generate a Bip32 HD wallet for the mnemonic and a user supplied password
// 	seed := bip39.NewSeed(mnemonic, "Secret Passphrase")

// 	masterKey, _ := bip32.NewMasterKey(seed)
// 	publicKey := masterKey.PublicKey()

// 	// Display mnemonic and keys
// 	fmt.Println("Mnemonic: ", mnemonic)
// 	fmt.Println("Master private key: ", masterKey)
// 	fmt.Println("Master public key: ", publicKey)

// }

// package main

// import (
// 	"crypto/aes"
// 	"crypto/cipher"
// 	"encoding/base64"
// 	"fmt"
// 	"log"

// 	hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
// )

// func main() {
// 	mnemonic := "tag volcano eight thank tide danger coast health above argue embrace heavy"
// 	wallet, err := hdwallet.NewFromMnemonic(mnemonic)
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	path := hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/0")
// 	account, err := wallet.Derive(path, false)
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	fmt.Println(account.Address.Hex()) // 0xC49926C4124cEe1cbA0Ea94Ea31a6c12318df947

// 	path = hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/1")
// 	account, err = wallet.Derive(path, false)
// 	if err != nil {
// 		log.Fatal(err)
// 	}

// 	fmt.Println(account.Address.Hex()) // 0x8230645aC28A4EdD1b0B53E7Cd8019744E9dD559
// }
