using Xunit;
using Nethereum.KeyStore;
using System.IO;
using System.Collections.Generic;
using Nethereum.Web3.Accounts;
using System.Threading.Tasks;
using Nethereum.Web3;
using Nethereum.Hex.HexTypes;
using Nethereum.RPC.TransactionReceipts;

namespace NetEthereumTest
{
    public class NetEthereumTests
    {
        public static Dictionary<string, string> _accounts = new Dictionary<string, string>();

        [Fact(DisplayName = "ShouldCreateKeyPair", Skip = "Should be confirmed if will need to use")]
        void ShouldCreateKeyPair()
        {
            var ecKey = Nethereum.Signer.EthECKey.GenerateKey();
            //Get the public address (derivied from the public key)
            var address = ecKey.GetPublicAddress();
            var privateKey = ecKey.GetPrivateKey();
            Assert.NotNull(privateKey);
        }

        [Theory(DisplayName = "ShouldCreateAccountInMemory", Skip = "Should be confirmed if will need to use")]
        [InlineData("Aa1234567","OriErez")]
        void ShouldCreateAccountInMemory(string password , string name)
        {
            CreateAccountInMemory(password, name);
        }

        [Fact(DisplayName = "ShouldTransferBetweenAccounts", Skip = "Should be confirmed if will need to use")]
        async Task ShouldTransferBetweenAccounts()
        {
            
            var addressTo = "0xe48f567c2555609ba489802a823510fb6ca85710";

            // A managed account is an account which is maintained by the client (Geth / Parity)
            //var account = CreateAccountInMemory(password, name);
            var account = new Account("32fea3dff88e23e30459e1235ec711a6a7f54359ba7eb5b15fbf18527124c1e8");
            var web3 = new Web3(account);

            //The transaction receipt polling service is a simple utility service to poll for receipts until mined
            var transactionPolling = new TransactionReceiptPollingService(web3.TransactionManager);

            var currentBalance = await web3.Eth.GetBalance.SendRequestAsync(addressTo);
            //assumed client is mining already

            //When sending the transaction using the transaction manager for a managed account, personal_sendTransaction is used.
            var transactionReceipt = await transactionPolling.SendRequestAsync(() =>
                web3.TransactionManager.SendTransactionAsync(account.Address, addressTo, new HexBigInteger(20))
            );

            var newBalance = await web3.Eth.GetBalance.SendRequestAsync(addressTo);

            Assert.Equal(currentBalance.Value + 20, newBalance.Value);
        }

        public Account CreateAccountInMemory(string password,string accountName)
        {
            //Generate a private key pair using SecureRandom
            var ecKey = Nethereum.Signer.EthECKey.GenerateKey();
            //Get the public address (derivied from the public key)
            var address = ecKey.GetPublicAddress();

            //Create a store service, to encrypt and save the file using the web3 standard
            var service = new KeyStoreService();

            var encryptedKey = service.EncryptAndGenerateDefaultKeyStoreAsJson(password, ecKey.GetPrivateKeyAsBytes(), address);

            var account = new Nethereum.Web3.Accounts.Account(ecKey.GetPrivateKeyAsBytes());

            var web3 = new Nethereum.Web3.Web3(account);

            _accounts[accountName] = encryptedKey;

            return account;
        }

        public string CreateAccount(string password, string path)
        {
            //Generate a private key pair using SecureRandom
            var ecKey = Nethereum.Signer.EthECKey.GenerateKey();
            //Get the public address (derivied from the public key)
            var address = ecKey.GetPublicAddress();

            //Create a store service, to encrypt and save the file using the web3 standard
            var service = new KeyStoreService();
            var encryptedKey = service.EncryptAndGenerateDefaultKeyStoreAsJson(password, ecKey.GetPrivateKeyAsBytes(), address);
            var fileName = service.GenerateUTCFileName(address);
            //save the File
            using (var newfile = File.CreateText(Path.Combine(path, fileName)))
            {
                newfile.Write(encryptedKey);
                newfile.Flush();
            }

            return fileName;
        }
    }
}
