using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using System.Xml.Linq;

namespace NetcashIframe
{
    public partial class frmNetcashDemo : Form
    {
        private const string postURL = "https://mobi.netcash.co.za/Authenticate.aspx";
        public frmNetcashDemo()
        {
            InitializeComponent();
            txtSVK.Text = "24ade73c-98cf-47b3-99be-cc7b867b3080"; // Do not use this key in production code; Apply for a software vendor key with Netcash
        }


        // !!!! NOTE: See these as access tokens. NEVER save them.
        private async void btnPOST_Click(object sender, EventArgs e)
        {

            string usr = txtUsername.Text;
            string pin = txtPin.Text;
            string xml = generateXML(
                                        Convert.ToInt32(txtBasepage.Text),
                                        txtSVK.Text, txtUsername.Text,
                                        txtPassword.Text,
                                        txtPin.Text
                                      );
            rtbRaw.Text = xml;


            await initWebviewControl(); // This is just for the demo (Webview2 Control)

            var message = frmNetcashDemo.Encrypt(xml, pin);
            string encData = String.Format("key={0}&message={1}", usr, message);
            Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(encData));
             
            var request = WebView21.CoreWebView2.Environment.CreateWebResourceRequest(postURL, "POST", stream, "Content-Type: application/x-www-form-urlencoded");
            WebView21.CoreWebView2.NavigateWithWebResourceRequest(request);

        }

        private void btnHtmlDemo_Click(object sender, EventArgs e)
        {
            string usr = txtUsername.Text;
            string pin = txtPin.Text;
            string xml = generateXML(
                                        Convert.ToInt32(txtBasepage.Text),
                                        txtSVK.Text, txtUsername.Text,
                                        txtPassword.Text,
                                        txtPin.Text
                                      );
            var message = frmNetcashDemo.Encrypt(xml, pin);
            string encData = String.Format("key={0}&message={1}", usr, message);
            rtbRaw.Text = generateTextHTML(usr, message);
        }

        private string generateXML(int basePage, string svk, string usr, string pwd, string pin)
        {
            XDocument doc = new XDocument(
                new XElement("SagePayRequest", // This element must remain as is for legacy purposes
                    new XElement("BasePage", basePage),
                    new XElement("SecurityHeader",
                        new XElement("SoftwareVendorKey", svk),
                        new XElement("Username", usr),
                        new XElement("Password", pwd),
                        new XElement("Pin", pin)
                        ),
                    // Need to add this (Legacy); 
                    new XElement("ConsumerDetails",
                        new XElement("Identifier", ""),
                        new XElement("Firstname", ""),
                        new XElement("Surname", ""),
                        new XElement("DateOfBirth", "1901-02-10T00:00:00")
                        )
                    )
                );

            return doc.ToString();
        }

        private string generateTextHTML(string key, string message)
        {
            XDocument htmlDoc = new XDocument(
                new XDocumentType("html", null, null, null),
                new XElement("html",
                    new XElement("head",
                        new XElement("title", "TEST POST"),
                        new XElement("meta", new XAttribute("charset", "utf-8"))
                    ),
                    new XElement("body",
                        new XElement("h1", "PLEASE DELETE THIS AFTER THE TEST - IT CONTAINS YOUR LOGIN DETAILS"),
                        new XElement("div",
                         new XElement("form",
                            new XAttribute("action", postURL),
                            new XAttribute("method", "POST"),
                            new XElement("input",
                                new XAttribute("type", "hidden"),
                                new XAttribute("name", "key"),
                                new XAttribute("value", key)),

                            new XElement("input",
                                new XAttribute("type", "hidden"),
                                new XAttribute("name", "message"),
                                new XAttribute("value", message)),
                            new XElement("button",
                                new XAttribute("type", "submit"),
                                "Submit Data")
                            )
                        )
                    )
                )
            );

            if (cbxOutput.Checked)
                htmlDoc.Save("output.html");

            return htmlDoc.ToString();
        }


        #region Cryptography
        public static string Encrypt(string clearText, string passKey)
        {
            byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(passKey, new byte[] { 0x49, 0x76, 0x61, 0x6E, 0x20, 0x4D, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
            string customreplace = Convert.ToBase64String(encryptedData);
            // Ensure Web-Safe
            customreplace = customreplace.Replace("/", "_");
            customreplace = customreplace.Replace("+", "|");
            customreplace = customreplace.Replace("=", "]");
            return HttpUtility.HtmlEncode(customreplace);
        }

        private static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (Rijndael alg = Rijndael.Create())
                {
                    alg.Key = Key;
                    alg.IV = IV;
                    using (CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearData, 0, clearData.Length);
                    }
                }
                return ms.ToArray();
            }
        }


        #endregion

        private async Task initWebviewControl()
        {
            await WebView21.EnsureCoreWebView2Async(null);
        }

    }
}
