using System;
using System.Text;
using System.Collections.Generic;
using System.IO;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Sockeye.Models;
using Sockeye.Util;



namespace Sockeye.Biz
{
    //Key generator controller
    public static class KeyFactory
    {

        public const string PLUGIN_MBI_KEY = "MBI - Minimal browser interface";
        public const string PLUGIN_WBI_KEY = "WBI - Web browser interface";
        public const string PLUGIN_QBI_KEY = "QBI - QuickBooks interface";
        public const string PLUGIN_QBOI_KEY = "QBOI - QuickBooks Online interface";
        public const string PLUGIN_PTI_KEY = "PTI - US Sage 50/Peachtree interface";
        public const string PLUGIN_QUICK_NOTIFICATION_KEY = "QuickNotification";
        public const string PLUGIN_EXPORT_TO_XLS_KEY = "ExportToXls";
        public const string PLUGIN_OUTLOOK_SCHEDULE_KEY = "OutlookSchedule";
        public const string PLUGIN_OLI_KEY = "AyaNovaOLI";
        public const string PLUGIN_IMPORT_EXPORT_CSV_DUPLICATE_KEY = "ImportExportCSVDuplicate";
        public const string PLUGIN_RI_KEY = "RI - Responsive Interface";


        //private static Dictionary<string, DateTime> _plugins;

        // //Generate a key message reply from a key selection object
        // //CALLED BY LicenseController Generate route
        // public static string GetKeyReply(dtoKeyOptions ko, LicenseTemplates t, rockfishContext ct)
        // {

        //     //case 3542
        //     ko.installByDate = System.DateTime.Now.AddYears(1);//changed from one month to one year
        //     string sKey = genKey(ko, ct);
        //     string sMsg = genMessage(sKey, ko, t);
        //     return sMsg;
        // }



        // //called by trialkeyrequesthandler.GenerateFromRequest
        // //get a trial key for named regTo        
        // public static string GetTrialKey(string regTo, bool lite, LicenseTemplates t, string authorizedUserKeyGeneratorStamp,
        // string emailAddress, rockfishContext ct)//case 3233
        // {
        //     DateTime dtoneMonth = System.DateTime.Now.AddMonths(1);
        //     long oneMonth = DateUtil.DateToEpoch(System.DateTime.Now.AddMonths(1));

        //     dtoKeyOptions ko = new dtoKeyOptions();

        //     //case 3233
        //     ko.emailAddress = emailAddress;
        //     ko.customerId = 0; //not a customer so trial 0

        //     ko.registeredTo = regTo;
        //     ko.supportExpiresDate = oneMonth;
        //     ko.isLite = lite;
        //     ko.installByDate = dtoneMonth;
        //     ko.authorizedUserKeyGeneratorStamp = authorizedUserKeyGeneratorStamp;
        //     if (lite)
        //     {
        //         ko.users = 1;
        //     }
        //     else
        //     {
        //         ko.users = 5;
        //     }

        //     ko.licenseType = "webRequestedTrial";

        //     ko.qbi = true;
        //     ko.qbiSupportExpiresDate = oneMonth;

        //     ko.qboi = true;
        //     ko.qboiSupportExpiresDate = oneMonth;

        //     ko.pti = true;
        //     ko.ptiSupportExpiresDate = oneMonth;

        //     ko.exportToXls = true;
        //     ko.exportToXlsSupportExpiresDate = oneMonth;

        //     ko.outlookSchedule = true;
        //     ko.outlookScheduleSupportExpiresDate = oneMonth;

        //     ko.oli = true;
        //     ko.oliSupportExpiresDate = oneMonth;

        //     ko.importExportCSVDuplicate = true;
        //     ko.importExportCSVDuplicateSupportExpiresDate = oneMonth;

        //     if (!lite)
        //     {
        //         ko.quickNotification = true;
        //         ko.quickNotificationSupportExpiresDate = oneMonth;

        //         ko.mbi = true;
        //         ko.mbiSupportExpiresDate = oneMonth;

        //         ko.wbi = true;
        //         ko.wbiSupportExpiresDate = oneMonth;

        //         ko.ri = true;
        //         ko.riSupportExpiresDate = oneMonth;
        //     }

        //     string sKey = genKey(ko, ct);
        //     string sMsg = genMessage(sKey, ko, t);
        //     return sMsg;

        // }


        //Take the key and the options and make a return message ready to send
        private static string genMessage(License l, bool isFirstLicenseForCustomer)
        {
            string sMessage = "";

            if (l.TrialMode)
            {
                sMessage = TemplateFullTrial;
            }
            else
            {
                if (isFirstLicenseForCustomer)
                    sMessage = TemplateFullNew;
                else //add-on or renewal                
                    sMessage = TemplateFullAddOn;

            }



            //token substitutions
            sMessage = sMessage.Replace("[LicenseExpiryDate]", l.MaintenanceExpire.ToString("D"));//https://github.com/dotnet/coreclr/issues/2317
            sMessage = sMessage.Replace("[LicenseDescription]", LicenseInfo(l));
            sMessage = sMessage.Replace("[LicenseKey]", l.Key);

            return sMessage;

        }




        // Extra info to display about key at top of key message      
        private static string LicenseInfo(License l)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("LICENSE DETAILS\r\n");
            // sb.Append("This key must be installed before: ");
            // sb.Append(ko.installByDate.ToString("D"));
            // sb.Append("\r\n");

            //if (kg.SelectedLicenseType == "Web requested trial")
            //{
            //    sb.Append("*** This temporary license key has been provided for limited evaluation purposes only *** \r\n");
            //    sb.Append("This license will expire and AyaNova usage will be restricted after: " + kg.Expires.ToLongDateString() + "\r\n\r\n");
            //}

            if (l.LicenseExpire != null)
            {
                sb.Append("*** This temporary license key is provided for evaluation use only pending payment ***\r\n");
                sb.Append($"This license will expire and AyaNova usage will be restricted after: {l.LicenseExpire}\r\n");
                sb.Append("\r\n");
                sb.Append("A permanent license key will be sent to you when payment \r\n" +
                    "has been received and processed.  There will be no extensions or \r\n" +
                    "exceptions.  Please send in payment early enough to allow for \r\n" +
                    "mail and processing time to ensure uninterrupted use of AyaNova. \r\n\r\n");
            }




            sb.Append("Registered to: ");
            sb.Append(l.RegTo);
            sb.Append("\r\n");

            //case 3233
            sb.Append("Fetch address: ");
            sb.Append(l.FetchEmail);
            sb.Append("\r\n");

            sb.Append("Fetch code: ");
            sb.Append(l.FetchCode);
            sb.Append("\r\n");


            sb.Append("Scheduleable resources: ");
            switch (l.Users)
            {
                case 1:
                    sb.AppendLine("1");
                    break;
                case 5:
                    sb.AppendLine("Up to 5");
                    break;
                case 10:
                    sb.AppendLine("Up to 10");
                    break;
                case 15:
                    sb.AppendLine("Up to 15");//case 3550
                    break;
                case 20:
                    sb.AppendLine("Up to 20");
                    break;
                case 50:
                    sb.AppendLine("Up to 50");
                    break;
                case 999:
                    sb.AppendLine("Up to 999");
                    break;
            }

            sb.AppendLine($"Support and updates until: {l.MaintenanceExpire}\r\n");
            var Plugs = LicenseToPluginsArray(l);
            if (Plugs.Count > 0)
            {
                sb.Append("\r\n");
                sb.Append("Plugins:\r\n");
                foreach (KeyValuePair<string, DateTime> kv in Plugs)
                {
                    sb.Append("\t");
                    sb.Append(kv.Key);
                    sb.Append(" support and updates until: ");
                    sb.Append(kv.Value.ToString("D"));
                    sb.Append("\r\n");
                }
            }

            return sb.ToString();
        }






        private static Dictionary<string, DateTime> LicenseToPluginsArray(License l)
        {
            Dictionary<string, DateTime> Plugs = new Dictionary<string, DateTime>();
            if (l.MBI)
                Plugs.Add(PLUGIN_MBI_KEY, (DateTime)l.MBIExpires);

            if (l.WBI)
                Plugs.Add(PLUGIN_WBI_KEY, (DateTime)l.WBIExpires);

            if (l.QBI)
                Plugs.Add(PLUGIN_QBI_KEY, (DateTime)l.QBIExpires);

            if (l.QBOI)
                Plugs.Add(PLUGIN_QBOI_KEY, (DateTime)l.QBOIExpires);

            if (l.PTI)
                Plugs.Add(PLUGIN_PTI_KEY, (DateTime)l.PTIExpires);

            if (l.QuickNotification)
                Plugs.Add(PLUGIN_QUICK_NOTIFICATION_KEY, (DateTime)l.QuickNotificationExpires);

            if (l.ExportToXLS)
                Plugs.Add(PLUGIN_EXPORT_TO_XLS_KEY, (DateTime)l.ExportToXLSExpires);

            if (l.OutlookSchedule)
                Plugs.Add(PLUGIN_OUTLOOK_SCHEDULE_KEY, (DateTime)l.OutlookScheduleExpires);

            if (l.OLI)
                Plugs.Add(PLUGIN_OLI_KEY, (DateTime)l.OLIExpires);

            if (l.ImportExportCSVDuplicate)
                Plugs.Add(PLUGIN_IMPORT_EXPORT_CSV_DUPLICATE_KEY, (DateTime)l.ImportExportCSVDuplicateExpires);

            if (l.RI)
                Plugs.Add(PLUGIN_RI_KEY, (DateTime)l.RIExpires);

            return Plugs;
        }

        /// <summary>
        /// Generate keycode based on passed in data
        /// This is called by both regular and trial license key routes
        /// </summary>
        /// <returns></returns>
        internal static void GenerateAndSetV7Key(License l)
        {

            StringBuilder sbKey = new StringBuilder();
            StringWriter sw = new StringWriter(sbKey);
            l.FetchCode = StringUtil.GenFetchCode();
            using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw))
            {
                w.Formatting = Newtonsoft.Json.Formatting.Indented;
                //outer object start
                w.WriteStartObject();
                w.WritePropertyName("AyaNovaLicenseKey");

                w.WriteStartObject();//start of key object

                w.WritePropertyName("SchemaVersion");
                w.WriteValue("7");

                //stamp a unique value in the key so it can be revoked later
                //used to use the digest value of the key for this with xml key
                //whole unix timestamp seconds but kept as a double to work beyond 2038
                w.WritePropertyName("Id");
                var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
                string sId = vv.ToString();
                if (sId.Contains(","))
                    sId = sId.Split('.')[0];
                w.WriteValue(sId);

                w.WritePropertyName("Created");
                w.WriteValue(System.DateTime.Now);

                w.WritePropertyName("Sub");
                w.WriteValue("true");

                w.WritePropertyName("RegisteredTo");
                w.WriteValue(l.RegTo);

                //case 3233
                w.WritePropertyName("EmailAddress");
                w.WriteValue(l.FetchEmail);

                w.WritePropertyName("FetchCode");

                w.WriteValue(l.FetchCode);

                //case 3187 - Source here
                //rockfish                  
                w.WritePropertyName("Source");
                w.WriteValue(StringUtil.ToHex("RFID" + "420"));


                w.WritePropertyName("InstallableUntil");
                w.WriteValue(l.MaintenanceExpire);

                w.WritePropertyName("TotalScheduleableUsers");
                w.WriteValue(l.Users.ToString());//Needs to be a string to match rockfish format

                w.WritePropertyName("Expires");
                w.WriteValue(l.MaintenanceExpire);

                if (l.LicenseExpire != null)
                {
                    w.WritePropertyName("LockDate");
                    w.WriteValue(l.LicenseExpire);

                }

                w.WritePropertyName("RequestedTrial");
                w.WriteValue(l.TrialMode.ToString());

                //PLUGINS
                w.WritePropertyName("Plugins");
                w.WriteStartObject();//start of key object
                w.WritePropertyName("Plugin");
                w.WriteStartArray();

                if (l.MBI)
                    AddLicensePlugin(w, PLUGIN_MBI_KEY, l.MBIExpires);

                if (l.WBI)
                    AddLicensePlugin(w, PLUGIN_WBI_KEY, l.WBIExpires);

                if (l.QBI)
                    AddLicensePlugin(w, PLUGIN_QBI_KEY, l.QBIExpires);

                if (l.QBOI)
                    AddLicensePlugin(w, PLUGIN_QBOI_KEY, l.QBOIExpires);

                if (l.PTI)
                    AddLicensePlugin(w, PLUGIN_PTI_KEY, l.PTIExpires);

                if (l.QuickNotification)
                    AddLicensePlugin(w, PLUGIN_QUICK_NOTIFICATION_KEY, l.QuickNotificationExpires);

                if (l.ExportToXLS)
                    AddLicensePlugin(w, PLUGIN_EXPORT_TO_XLS_KEY, l.ExportToXLSExpires);

                if (l.OutlookSchedule)
                    AddLicensePlugin(w, PLUGIN_OUTLOOK_SCHEDULE_KEY, l.OutlookScheduleExpires);

                if (l.OLI)
                    AddLicensePlugin(w, PLUGIN_OLI_KEY, l.OLIExpires);

                if (l.ImportExportCSVDuplicate)
                    AddLicensePlugin(w, PLUGIN_IMPORT_EXPORT_CSV_DUPLICATE_KEY, l.ImportExportCSVDuplicateExpires);

                if (l.RI)
                    AddLicensePlugin(w, PLUGIN_RI_KEY, l.RIExpires);

                //end of plugins array
                w.WriteEnd();

                //end of plugins object
                w.WriteEndObject();

                //end of AyaNova/AyaNovaLite key object
                w.WriteEndObject();

                //close outer 'wrapper' object brace }
                w.WriteEndObject();

            }//end of using statement


            // ## CALCULATE SIGNATURE

            //GET JSON as a string with whitespace stripped outside of delimited strings
            //http://stackoverflow.com/questions/8913138/minify-indented-json-string-in-net
            string keyNoWS = System.Text.RegularExpressions.Regex.Replace(sbKey.ToString(), "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1");


            //**** Note this is our real 2016 private key
            var privatePEM = @"-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAz7wrvLDcKVMZ31HFGBnLWL08IodYIV5VJkKy1Z0n2snprhSi
u3izxTyz+SLpftvKHJpky027ii7l/pL9Bo3JcjU5rKrxXavnE7TuYPjXn16dNLd0
K/ERSU+pXLmUaVN0nUWuGuUMoGJMEXoulS6pJiG11yu3BM9fL2Nbj0C6a+UwzEHF
mns3J/daZOb4gAzMUdJfh9OJ0+wRGzR8ZxyC99Na2gDmqYglUkSMjwLTL/HbgwF4
OwmoQYJBcET0Wa6Gfb17SaF8XRBV5ZtpCsbStkthGeoXZkFriB9c1eFQLKpBYQo2
DW3H1MPG2nAlQZLbkJj5cSh7/t1bRF08m6P+EQIDAQABAoIBAQCGvTpxLRXgB/Kk
EtmQBEsMx9EVZEwZeKIqKuDsBP8wvf4/10ql5mhT6kehtK9WhSDW5J2z8DtQKZMs
SBKuCZE77qH2CPp9E17SPWzQoRbaW/gDlWpYhgf8URs89XH5zxO4XtXKw/4omRlV
zLYiNR2pifv0EHqpOAg5KGzewdEo4VgXgtRWpHZLMpH2Q0/5ZIKMhstI6vFHP1p7
jmU4YI6uxiu7rVrZDmIUsAGoTdMabNqK/N8hKaoBiIto0Jn1ck26g+emLg8m160y
Xciu5yFUU+PP1SJMUs+k1UnAWf4p46X9jRLQCBRue9o0Ntiq/75aljRoDvgdwDsR
mg4ZANqxAoGBAPBoM5KoMZ4sv8ZFv8V+V8hgL5xiLgGoiwQl91mRsHRM/NQU5A/w
tH8nmwUrJOrksV7kX9228smKmoliTptyGGyi1NPmSkA7cN9YYnENoOEBHCVNK9vh
P+bkbMYUDNMW4fgOj09oXtQtMl5E2B3OTGoNwZ2w13YQJ8RIniLPsX7nAoGBAN01
eQNcUzQk9YrFGTznOs8udDLBfigDxaNnawvPueulJdBy6ZXDDrKmkQQA7xxl8YPr
dNtBq2lOgnb6+smC15TaAfV/fb8BLmkSwdn4Fy0FApIXIEOnLq+wjkte98nuezl8
9KXDzaqNI9hPuk2i36tJuLLMH8hzldveWbWjSlRHAoGBAKRPE7CQtBjfjNL+qOta
RrT0yJWhpMANabYUHNJi+K8ET2jEPnuGkFa3wwPtUPYaCABLJhprB9Unnid3wTIM
8RSO1ddd9jGgbqy3w9Bw+BvQnmQAMpG9iedNB+r5mSpM4XSgvuIO+4EYwuwbMXpt
nVx+um4Eh75xnDxTRYGVYkLRAoGAaZVpUlpR+HSfooHbPv+bSWKB4ewLPCw4vHrT
VErtEfW8q9b9eRcmP81TMFcFykc6VN4g47pfh58KlKHM7DwAjDLWdohIy89TiKGE
V3acEUfv5y0UoFX+6ara8Ey+9upWdKUY3Lotw3ckoc3EPeQ84DQK7YSSswnAgLaL
mS/8fWcCgYBjRefVbEep161d2DGruk4X7eNI9TFJ278h6ydW5kK9aTJuxkrtKIp4
CYf6emoB4mLXFPvAmnsalkhN2iB29hUZCXXSUjpKZrpijL54Wdu2S6ynm7aT97NF
oArP0E2Vbow3JMxq/oeXmHbrLMLQfYyXwFmciLFigOtkd45bfHdrbA==
-----END RSA PRIVATE KEY-----";

            PemReader pr = new PemReader(new StringReader(privatePEM));
            AsymmetricCipherKeyPair keys = (AsymmetricCipherKeyPair)pr.ReadObject();
            var encoder = new UTF8Encoding(false, true);
            var inputData = encoder.GetBytes(keyNoWS);
            var signer = SignerUtilities.GetSigner("SHA256WITHRSA");
            signer.Init(true, keys.Private);
            signer.BlockUpdate(inputData, 0, inputData.Length);
            var sign = signer.GenerateSignature();
            var signature = Convert.ToBase64String(sign);


            System.Text.StringBuilder sbOut = new StringBuilder();
            sbOut.AppendLine("[KEY");
            sbOut.AppendLine(sbKey.ToString());
            sbOut.AppendLine("KEY]");
            sbOut.AppendLine("[SIGNATURE");
            sbOut.AppendLine(signature);
            sbOut.AppendLine("SIGNATURE]");

            l.Key = sbOut.ToString();





        }



        private static void AddLicensePlugin(Newtonsoft.Json.JsonWriter w, string pluginName, DateTime? pluginExpires)
        {



            //this is adding it to the actual key
            w.WriteStartObject();
            w.WritePropertyName("Item");
            w.WriteValue(pluginName);

            w.WritePropertyName("SubscriptionExpires");
            w.WriteValue(pluginExpires);

            w.WriteEndObject();
            //----------------
        }


        #region Templates
        private static string TemplateFullNew
        {
            get
            {
                return @"Thank you for your purchase and welcome to the   
world-wide community of AyaNova users!   
   
Below is your activation key instructions for entry into the latest trial version
of AyaNova 7 that you previously downloaded from our website,   
installed and tested for suitability.   
 
Be sure to review and implement the backup procedures for AyaNova  
as outlined in the AyaNova online Help document from http://www.ayanova.com/onlinehelp.htm   
 
Reminder: no physical product will be shipped to you, this license key  
fulfills your order in full.   
   
PURCHASING ADDITIONAL LICENSES   
When purchasing additional licenses in future be sure to use the same registration name
and registered email address used when you purchased this key.  
  
Additional AyaNova licenses can be purchased via the link at   
http://www.ayanova.com/purchase.htm   
   
   
HELP AND SUPPORT RESOURCES   
 
ONLINE: , l.
AyaNova web site:   
http://www.ayanova.com   
 
Answers to frequently asked questions:   
http://www.ayanova.com/faqAnswers.htm   
 
Technical support forum:   
http://forum.ayanova.com   
 
Latest AyaNova version update information:  
Downloads and help documentation: 
http://www.ayanova.com/download.htm 
http://www.ayanova.com/onlinehelp.htm

PURCHASING ADDITIONAL LICENSES   
When purchasing additional license subscriptions in future do use the same registration name
and registered email address used when you purchased your original licenses to ensure fastest processing.

[LicenseDescription] 

HOW TO INSTALL YOUR LICENSE KEY

1. Ensure no other users are running AyaNova

2. Log in as the AyaNova Administrator
(default login is manager with password letmein if not yet changed).

3. Select Help->License from the main menu to open the license key form.

4. Select the menu option Fetch license and in the form that opens, copy and paste (preferable) or enter manually your Fetch address and Fetch code exactly as it appears above in 'License Details' section of this message.
(If you do not see the 'Fetch license' menu option you need to upgrade to the latest version of AyaNova first)

5.Click on the accept button, AyaNova will fetch the license key from our server and install it automatically";
            }
        }



        private static string TemplateFullAddOn
        {
            get
            {
                return @"Thank you for your continued support!

This license key when applied, replaces your previous key which is no longer required.

[LicenseDescription] 

HOW TO INSTALL YOUR LICENSE KEY

1. Be sure you are running the latest version before proceeding:
https://www.ayanova.com/changeloglatest.htm

2. Ensure no other users are running AyaNova

3. Log in as the AyaNova Administrator
(default login is manager with password letmein if not yet changed).

4. Select Help->License from the main menu to open the license key form.

5. Select the menu option Fetch license and in the form that opens, copy and paste (preferable) or enter manually your Fetch address and Fetch code exactly as it appears above in 'License Details' section of this message.
(If you do not see the 'Fetch license' menu option you need to upgrade to the latest version of AyaNova first)

6. Click on the accept button, AyaNova will fetch the license key from our server and install it automatically";
            }
        }

        private static string TemplateFullTrial
        {
            get
            {
                return @"Thank you for evaluating AyaNova 7 and its optional add-ons. 
  
Below are instructions for license entry into the 
latest trial version of AyaNova that you previously downloaded from our website.  
  
You must apply this license before [LicenseExpiryDate]. 
 
  
HELP AND SUPPORT RESOURCES   

ONLINE:
AyaNova web site:  
http://www.ayanova.com  

Answers to frequently asked questions:   
http://www.ayanova.com/faqAnswers.htm  

Technical support forum:   
http://forum.ayanova.com  

Latest AyaNova version update information: 
Downloads and help documentation: 
http://www.ayanova.com/download.htm 
http://www.ayanova.com/onlinehelp.htm 

 
[LicenseDescription]


HOW TO INSTALL YOUR LICENSE KEY

1. Ensure no other users are running AyaNova

2. Log in as the AyaNova Administrator
(default login is manager with password letmein if not yet changed).

3. Select Help->License from the main menu to open the license key form.

4. Select the menu option Fetch license and in the form that opens,  copy  and paste (preferable) or enter manually your Fetch address and Fetch code exactly as it appears above in License Details section.
(If you do not see the 'Fetch license' menu option you need to upgrade to the latest version of AyaNova first)

5. Click on the accept button, AyaNova will fetch the license key from our server and install it automatically";
            }
        }



        #endregion templates




        //eoc
    }
    //eons
}