using DotNetKit.com.payone.serviceprovider;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DotNetKit
{
    public partial class MerchantRequestParams : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
				
        }

        protected void BtnSubmit_Click(object sender, EventArgs e)
        {
            var merchantId = Request.Params["merchantId"];

            JavaScriptSerializer ser = new JavaScriptSerializer();
            string reqParams = "{";


            var count = Request.Form.AllKeys.Length;
            var ctr = 0;
            foreach (String s in Request.Form.AllKeys)
            {
                ctr += 1;
                reqParams += s + ": \"" + Request.Form[s] + "\"";
                if (ctr != count)
                    reqParams += ",";

            }

            reqParams += "}";



            System.Collections.Specialized.NameValueCollection myform = Request.Form;

            IDictionary<string, string> merchantParamsDictionary = myform.Cast<string>().Select(s => new { Key = s, Value = myform[s] }).ToDictionary(p => p.Key, p => p.Value);
            var merchantParamsJson = MyDictionaryToJson(merchantParamsDictionary);
            var objMerchantParams = ser.Deserialize<MerchantParams>(merchantParamsJson);
            merchantParamsJson = ser.Serialize(objMerchantParams); // stripped unwanted asp.net properties added in JSON

            string encryptedParams = EncryptPaymentRequest(merchantParamsJson);
            ProcessPaymentRequest(encryptedParams, merchantId);
        }

        public string MyDictionaryToJson(IDictionary<string, string> dict)
        {
            var entries = dict.Select(d => string.Format("\"{0}\": \"{1}\"", d.Key, string.Join(",", d.Value)));
            return "{" + string.Join(",", entries) + "}";
        }

        public string EncryptPaymentRequest(string merchantParamsJson)
        {
            //add the Transaction Posting URL	
            /* 
                Merchant has to enter the Merchant Id shared by 1Pay in the below variable 'merchantId' and pass in the Request along with encrypted Request Data.
                Merchant has to enter the API Key shared by 1Pay in the below variable 'merchantEncryptionKey' to Encrypt the Transaction Request.
                Algorithm used for encryption is AES.
                Merchant Encryption Key will be different for TEST and PRODUCTION environment.
            */
            String merchantId = "M0002";
            String merchantEncryptionKey = "jpuT6032jpuT6032"; //16 Charachter String
            String encryptedText = string.Empty;

            try
            {

                string original = merchantParamsJson;  //"Here is some data to encrypt!";

                System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
                AesManaged tdes = new AesManaged();
                tdes.Key = UTF8.GetBytes(merchantEncryptionKey);
                tdes.Mode = CipherMode.ECB;
                tdes.Padding = PaddingMode.PKCS7;
                ICryptoTransform crypt = tdes.CreateEncryptor();
                //byte[] plain = Encoding.UTF8.GetBytes("{\"merchantId\":\"M0002\",\"ApiKey\":\"jpuT6032\",\"txnId\":\"1234567890\",\"amount\":\"10.00\",\"DateTime\":\"\\/Date(1547311525000)\\/\",\"CustMail\":\"test@test.com\",\"CustMobile\":\"9876543210\",\"UDF1\":\"NA\",\"UDF2\":\"NA\",\"ReturnUrl\":\"www.merchantUrl.com/merchantResponseProcessor.jsp\",\"IsMultiSettlement\":\"0\",\"ProductId\":\"DEFAULT\",\"ChannelId\":\"0\",\"TxnType\":\"DIRECT\",\"UDF3\":\"NA\",\"UDF4\":\"NA\",\"UDF5\":\"NA\",\"InstrumentId\":\"NA\",\"CardDetails\":\"NA\",\"CardType\":\"NA\"}");
                //byte[] plain = Encoding.UTF8.GetBytes("{\"merchantId\":\"M0002\",\"apiKey\":\"jpuT6032\",\"txnId\":\"1234567892\",\"amount\":\"10.00\",\"dateTime\":\"2019-01-19 20:15:25\",\"custMail\":\"test@test.com\",\"custMobile\":\"9876543210\",\"udf1\":\"NA\",\"udf2\":\"NA\",\"returnURL\":\"http://139.59.1.254:8080/payone/merchantResponse.jsp\",\"isMultiSettlement\":\"0\",\"productId\":\"DEFAULT\",\"channelId\":\"0\",\"txnType\":\"DIRECT\",\"udf3\":\"NA\",\"udf4\":\"NA\",\"udf5\":\"NA\",\"instrumentId\":\"NA\",\"cardDetails\":\"NA\",\"cardType\":\"NA\"}");
                byte[] plain = Encoding.UTF8.GetBytes(merchantParamsJson);
                byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
                encryptedText = Convert.ToBase64String(cipher);
                System.Console.WriteLine(encryptedText);

            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }

            return encryptedText;
        }
        public string ProcessPaymentRequest(string merchantParamsJson, string merchantId)
        {
            String tranStatus = null;
            String message = null;
            String errorCode = null;
            JavaScriptSerializer ser = new JavaScriptSerializer();
            //add the Transaction Posting URL	
            String reqUrl = "http://139.59.1.254:8080/onepayVAS/payprocessor";
            string responseString = string.Empty;


            //======================================= Server Side Form Post ===========================================================

            //string formId = "onePayForm";

            //StringBuilder htmlForm = new StringBuilder();
            //htmlForm.AppendLine("<html>");
            //htmlForm.AppendLine(String.Format("<body onload='document.forms[\"{0}\"].submit()'>", formId));
            //htmlForm.AppendLine(String.Format("<form id='{0}' method='POST' action='{1}'>", formId, Url));
            //htmlForm.AppendLine(String.Format("<input type='hidden' name='reqData' id='reqData' value='{0}' />", merchantParamsJson));
            //htmlForm.AppendLine(String.Format("<input type='hidden' name='merchantId' id='merchantId' value='{0}' />", merchantId));
            //htmlForm.AppendLine("</form>");
            //htmlForm.AppendLine("</body>");
            //htmlForm.AppendLine("</html>");

            //HttpContext.Current.Response.Clear();
            //HttpContext.Current.Response.Write(htmlForm.ToString());
            //HttpContext.Current.Response.End();

            //=========================================================================================================================

            //var request = (HttpWebRequest)WebRequest.Create(reqUrl);

            try
            {
                var postData = string.Format("reqData={0}&merchantId={1}", merchantParamsJson.Trim(), merchantId);
                var data = Encoding.UTF8.GetBytes(postData);

                HttpResponseMessage response;

                using (var handler = new HttpClientHandler())
                using (var client = new HttpClient(handler))
                {
                    using (var content = new StringContent(postData, Encoding.UTF8, "application/json"))
                    {
                        client.Timeout = TimeSpan.FromMinutes(5);
                        response = client.PostAsync(new Uri(reqUrl), content).Result;
                    }
                }

                if (response.IsSuccessStatusCode)
                {
                    var responseResult = response.Content.ReadAsStringAsync();
                    responseResult.Wait();
                    responseString = responseResult.Result;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }

            Console.WriteLine("verification started");

            if (!string.IsNullOrEmpty(responseString))
            {
				
				
				// Here please read response and deserialize that response into 'PayproceesResponseClass' class (create class same as 'VerificationResponse' in VerificationUtil.cs file)			
				//var payresponse =  ser.Deserialize<PayproceesResponseClass>(responseString);
                
				String txn_id = payresponse.txn_id; // Put Here Merchant transaction id from the response;			
				
                VerificationUtil objVerificationUtil = new VerificationUtil();

                
                String verParams = "merchantId=" + merchantId + "&txnId=" + txn_id;
                String verUrl = "https://hdfcprodsigning.in/onepayVAS/getTxnDetails";

                var verResp = objVerificationUtil.VerificationCall(verUrl, verParams);
                if (verResp.resp_code == "00000" && verResp.trans_status == "ok")
                {
                    tranStatus = "Ok";
                    message = "Transaction Successful.";
                    errorCode = "00000";
                }
                else
                {
                    tranStatus = "F";
                    errorCode = "FFFFF";
                    message = "Transaction Failed.";
                }

                Console.WriteLine("::: tranStatus : " + tranStatus);
                Console.WriteLine("::: errorCode : " + errorCode);
                Console.WriteLine("::: message : " + message);

				

            }

            return responseString;
        }

    }

    [Serializable]
    public class MerchantParams
    {
        [Required]
        public string merchantId { get; set; }

        [Required]
        public string apiKey { get; set; }

        [Required]
        public string txnId { get; set; } // Merchant Order Number

        [Required]
        public string amount { get; set; }

        [Required]
        public string dateTime { get; set; }

        [Required]
        public string custMail { get; set; }

        [Required]
        public string custMobile { get; set; }

        [Required]
        public string udf1 { get; set; }

        [Required]
        public string udf2 { get; set; }

        [Required]
        public string returnURL { get; set; }

        [Required]
        public string isMultiSettlement { get; set; }

        [Required]
        public string productId { get; set; }

        [Required]
        public string channelId { get; set; }

        [Required]
        public string txnType { get; set; }
        public string udf3 { get; set; }
        public string udf4 { get; set; }
        public string udf5 { get; set; }
        public string instrumentId { get; set; }
        public string cardDetails { get; set; }
        public string cardType { get; set; }

    }



    public class RijndaelClass
    {
        public static void Main()
        {
            try
            {

                string original = "Here is some data to encrypt!";

                // Create a new instance of the RijndaelManaged 
                // class.  This generates a new key and initialization  
                // vector (IV). 
                using (RijndaelManaged myRijndael = new RijndaelManaged())
                {

                    myRijndael.GenerateKey();
                    myRijndael.GenerateIV();
                    // Encrypt the string to an array of bytes. 
                    byte[] encrypted = EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV);

                    // Decrypt the bytes to a string. 
                    string roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);

                    //Display the original data and the decrypted data.
                    Console.WriteLine("Original:   {0}", original);
                    Console.WriteLine("Round Trip: {0}", roundtrip);
                }

            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
        }

        public static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption. 
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream. 
            return encrypted;

        }

        public static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");

            // Declare the string used to hold 
            // the decrypted text. 
            string plaintext = null;

            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for decryption. 
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {

                            // Read the decrypted bytes from the decrypting stream 
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }

            }

            return plaintext;

        }
    }
}