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.Util;
using Sockeye.Models;




namespace Sockeye.Biz
{
    //Key generator controller
    public static class RavenKeyFactory
    {
        //Jan 2023 values
        public const int TRIAL_KEY_SUBSCRIPTION_PERIOD_DAYS = 7;
        public const int TRIAL_KEY_SUBSCRIPTION_CUSTOMER_USERS = 25555;//SEEDING required        
        public const int TRIAL_KEY_SUBSCRIPTION_MAX_DATA_GB = 20;
        public const int TRIAL_KEY_PERPETUAL_PERIOD_DAYS = 14;
        public const int TRIAL_KEY_USERS = 5000;//SEEDING required minimum

        //Unlicensed token
        private const string UNLICENSED_TOKEN = "UNLICENSED";

        //REVOKED token
        public const string REVOKED_TOKEN = "REVOKED";

        //LICENSE USER COUNT FEATURES

        //SUBSCRIPTION
        private const string ACTIVE_INTERNAL_USERS_FEATURE_NAME = "ActiveInternalUsers";
        private const string ACTIVE_CUSTOMER_USERS_FEATURE_NAME = "ActiveCustomerUsers";
        private const string MAXIMUM_DATA_GB_FEATURE_NAME = "MaximumDataGB";


        //Add-on's / integrations

        //This feature name means it's a trial key
        private const string TRIAL_FEATURE_NAME = "TrialMode";

        /// <summary>
        /// RAVEN key generator
        /// </summary>
        /// <returns></returns>
        internal static void GenerateAndSetRavenKey(License l)
        {
            if (string.IsNullOrWhiteSpace(l.RegTo))
                throw new ArgumentException("RegisteredTo is required", "RegisteredTo");

            if (string.IsNullOrWhiteSpace(l.DbId))
                throw new ArgumentException("DBId is required", "DbId");

            //license serial number
            var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
            string sId = vv.ToString();
            if (sId.Contains(","))
                sId = sId.Split('.')[0];

            StringBuilder sbKey = new StringBuilder();
            StringWriter sw = new StringWriter(sbKey);

            using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw))
            {
                w.Formatting = Newtonsoft.Json.Formatting.Indented;

                //outer object start
                w.WriteStartObject();

                w.WritePropertyName("Key");

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

                w.WritePropertyName("LicenseFormat");
                w.WriteValue("8");

                w.WritePropertyName("Id");
                w.WriteValue(sId);

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

                w.WritePropertyName("DBID");
                w.WriteValue(l.DbId);

                w.WritePropertyName("Perpetual");
                w.WriteValue(l.PGroup == ProductGroup.RavenPerpetual);

                w.WritePropertyName("LicenseExpiration");
                w.WriteValue(l.LicenseExpire);

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

                //FEATURES
                w.WritePropertyName("Features");
                w.WriteStartArray();

                if (l.TrialMode)
                {
                    w.WriteStartObject();
                    w.WritePropertyName("Name");
                    w.WriteValue(TRIAL_FEATURE_NAME);
                    w.WriteEndObject();
                }

                //USERS
                w.WriteStartObject();
                w.WritePropertyName("Name");
                w.WriteValue(ACTIVE_INTERNAL_USERS_FEATURE_NAME);
                w.WritePropertyName("Count");
                w.WriteValue(l.Users);
                w.WriteEndObject();

                if (l.PGroup == ProductGroup.RavenSubscription)
                {
                    //CUSTOMER USERS
                    w.WriteStartObject();
                    w.WritePropertyName("Name");
                    w.WriteValue(ACTIVE_CUSTOMER_USERS_FEATURE_NAME);
                    w.WritePropertyName("Count");
                    w.WriteValue(l.CustomerUsers);
                    w.WriteEndObject();

                    //MAX DATA GB
                    w.WriteStartObject();
                    w.WritePropertyName("Name");
                    w.WriteValue(MAXIMUM_DATA_GB_FEATURE_NAME);
                    w.WritePropertyName("Count");
                    w.WriteValue(l.MaxDataGB);
                    w.WriteEndObject();

                }

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

                //End of "Key" property                  
                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();

        }


        #region old stuff
        #region license classes

        // //DTO object returned on license query
        // public class LicenseFeature
        // {
        //     //name of feature / product
        //     public string Feature { get; set; }

        //     //Optional count for items that require it
        //     public long Count { get; set; }

        // }

        // //DTO object for parsed key
        // internal class AyaNovaLicenseKey
        // {
        //     public AyaNovaLicenseKey()
        //     {
        //         Features = new List<LicenseFeature>();
        //         RegisteredTo = UNLICENSED_TOKEN;
        //         //Id = RegisteredTo;
        //         LicenseFormat = "8";

        //         var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
        //         string sId = vv.ToString();
        //         if (sId.Contains(","))
        //             sId = sId.Split('.')[0];
        //         Id = sId;
        //     }

        //     public override string ToString()
        //     {

        //         System.Text.StringBuilder sb = new StringBuilder();
        //         sb.AppendLine($"Registered to: {RegisteredTo}");
        //         sb.AppendLine($"Database id: {DbId}");
        //         sb.AppendLine($"Type: {(Perpetual ? "Perpetual" : "Subscription")}");
        //         if (WillExpire)
        //             sb.AppendLine($"Available for use until: {LicenseExpiration.ToLongDateString()}");
        //         if (Perpetual)
        //             sb.AppendLine($"Support and updates available until: {MaintenanceExpiration.ToLongDateString()}");
        //         foreach (LicenseFeature f in Features)
        //         {
        //             if (f.Feature == TRIAL_FEATURE_NAME)
        //             {
        //                 sb.AppendLine("Temporary license for evaluation");
        //                 continue;
        //             }


        //             //default for items added later not tokenized
        //             if (f.Count > 0)
        //                 sb.AppendLine($"{f.Feature}: {f.Count}");
        //             else
        //                 sb.AppendLine($"{f.Feature}");
        //         }
        //         return sb.ToString();
        //     }


        //     public bool IsEmpty
        //     {
        //         get
        //         {
        //             //Key is empty if it's not registered to anyone or there are no features in it
        //             return string.IsNullOrWhiteSpace(RegisteredTo) || (Features == null || Features.Count == 0);
        //         }
        //     }

        //     /// <summary>
        //     /// Fetch the license status of the feature in question
        //     /// </summary>
        //     /// <param name="Feature"></param>
        //     /// <returns>LicenseFeature object or null if there is no license</returns>
        //     public LicenseFeature GetLicenseFeature(string Feature)
        //     {
        //         if (IsEmpty)
        //             return null;

        //         string lFeature = Feature.ToLowerInvariant();

        //         foreach (LicenseFeature l in Features)
        //         {
        //             if (l.Feature.ToLowerInvariant() == lFeature)
        //             {
        //                 return l;
        //             }
        //         }
        //         return null;
        //     }


        //     /// <summary>
        //     /// Check for the existance of license feature
        //     /// </summary>
        //     /// <param name="Feature"></param>
        //     /// <returns>bool</returns>
        //     public bool HasLicenseFeature(string Feature)
        //     {
        //         if (IsEmpty)
        //             return false;

        //         string lFeature = Feature.ToLowerInvariant();

        //         foreach (LicenseFeature l in Features)
        //         {
        //             if (l.Feature.ToLowerInvariant() == lFeature)
        //             {
        //                 return true;
        //             }
        //         }
        //         return false;
        //     }


        //     public bool WillExpire
        //     {
        //         get
        //         {
        //             return LicenseExpiration < DateUtil.EmptyDateValue;
        //         }
        //     }


        //     public bool LicenseExpired
        //     {
        //         get
        //         {
        //             return LicenseExpiration > DateTime.Now;
        //         }
        //     }

        //     public bool MaintenanceExpired
        //     {
        //         get
        //         {
        //             return MaintenanceExpiration > DateTime.Now;
        //         }
        //     }


        //     public bool TrialLicense
        //     {
        //         get
        //         {
        //             return HasLicenseFeature(TRIAL_FEATURE_NAME);
        //         }
        //     }



        //     public string LicenseFormat { get; set; }
        //     public string Id { get; set; }
        //     public string RegisteredTo { get; set; }
        //     public string DbId { get; set; }
        //     public bool Perpetual { get; set; }
        //     public DateTime LicenseExpiration { get; set; }
        //     public DateTime MaintenanceExpiration { get; set; }
        //     public List<LicenseFeature> Features { get; set; }


        // }
        #endregion





        // public static string GetRavenTrialKey(License l)//string dbid, string CompanyName, bool Perpetual)
        // {

        //     //Build a sample test key, sign it and return it
        //     AyaNovaLicenseKey k = new AyaNovaLicenseKey();
        //     k.LicenseFormat = "8";
        //     k.RegisteredTo = l.RegTo;
        //     k.DbId = l.DbId;
        //     k.Perpetual = l.PGroup == ProductGroup.RavenPerpetual;

        //     //flag as trial key not regular key
        //     k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 });
        //     if (k.Perpetual)
        //     {
        //         //trial period time limit

        //         //Normal code, uncomment this when  done testing expiration dates of perpetual
        //         k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);

        //         //Testing code for 3 minute long evaluation license in case need to test with a key that expires 
        //         // #warning FYI ROCKFISH is SET TO GENERATE A VERY SHORT TEST KEY
        //         //                 k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddMinutes(3); //TEST VALUE FOR DIAGNOSING LICENSE EXPIRATION ISSUES

        //         //5k inside staff users will cover huge seeding level easily
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 });
        //     }
        //     else
        //     {
        //         //SUBSCRIPTION
        //         //trial period time limit
        //         k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);//NOTE: this preserves the current time, should it be set to midnight or something?

        //         //20k customer contacts will cover huge seeding level easily
        //         //5k inside staff users will cover huge seeding level easily
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 });
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_CUSTOMER_USERS_FEATURE_NAME, Count = 20000 });
        //         k.Features.Add(new LicenseFeature() { Feature = MAXIMUM_DATA_GB_FEATURE_NAME, Count = 20 });
        //     }
        //     return GenerateRavenKey(k);
        // }


        // //TESTING ONLY this is for development purposes only
        // //No external usage
        // public static string GetRavenTestKey(string dbid, bool Perpetual)
        // {
        //     //Build a sample test key, sign it and return it
        //     AyaNovaLicenseKey k = new AyaNovaLicenseKey();
        //     k.LicenseFormat = "8";
        //     k.RegisteredTo = "GZ TestCo Inc.";
        //     k.DbId = dbid;
        //     k.Perpetual = Perpetual;
        //     if (Perpetual)
        //     {
        //         k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);
        //         //5k inside staff users will cover huge seeding level easily
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 });
        //     }
        //     else
        //     {
        //         //SUBSCRIPTION
        //         k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);

        //         //20k customer contacts will cover huge seeding level easily
        //         //5k inside staff users will cover huge seeding level easily
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 });
        //         k.Features.Add(new LicenseFeature() { Feature = ACTIVE_CUSTOMER_USERS_FEATURE_NAME, Count = 20000 });
        //         k.Features.Add(new LicenseFeature() { Feature = MAXIMUM_DATA_GB_FEATURE_NAME, Count = 20 });

        //     }

        //     k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 });
        //     return GenerateRavenKey(k);
        // }

        #endregion old stuff

        //eoc
    }
    //eons
}
