using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Sockeye.Models;
using Sockeye.Util;

namespace Sockeye.Biz
{


    /// <summary>
    /// Process purchases into licenses
    ///
    /// </summary>
    internal static class SockBotProcessPurchasesIntoLicenses
    {
        private static ILogger log = Sockeye.Util.ApplicationLogging.CreateLogger("SockBotProcessPurchasesIntoLicenses");
        private static DateTime lastSweep = DateTime.MinValue;
        private static TimeSpan PROCESS_V7_AGE = new TimeSpan(0, 5, 0);//Don't process a v7 order until at least 5 minutes old as it doesn't always come in at once
#if (DEBUG)
        private static TimeSpan PROCESS_EVERY_INTERVAL = new TimeSpan(0, 0, 30);//every 30 seconds during development
#else
        private static TimeSpan PROCESS_EVERY_INTERVAL = new TimeSpan(0, 5, 10);//every 5 minutes 
#endif
        ////////////////////////////////////////////////////////////////////////////////////////////////
        // DoSweep
        //
        public static async Task DoWorkAsync()
        {
            //This will get triggered roughly every minute, but we don't want to check that frequently
            if (DateTime.UtcNow - lastSweep < PROCESS_EVERY_INTERVAL)
                return;

            if (ServerBootConfig.MIGRATING) return;//don't do this during migration (migration is one time only so can remove after up and running)

            log.LogDebug("Process purchases into licenses starting");
            await ProcessPurchasesIntoLicenses();

            lastSweep = DateTime.UtcNow;
        }

        private static async Task ProcessPurchasesIntoLicenses()
        {
            using (AyContext ct = Sockeye.Util.ServiceProviderProvider.DBContext)
            {

                //get a list of all actionable purchases grouped by customer id
                var purchaseList = (await ct.Purchase.AsNoTracking()
                                 .Where(z => z.Processed == false
                                             && z.LicenseId == null
                                             && z.CustomerId != null
                                             && (z.PGroup == ProductGroup.AyaNova7 || z.PGroup == ProductGroup.RavenPerpetual || z.PGroup == ProductGroup.RavenSubscription))
                                 .OrderByDescending(z => z.PurchaseDate)
                                 .ToListAsync()).GroupBy(z => (long)z.CustomerId);

                try
                {
                    foreach (var purchaseGroup in purchaseList)
                    {
                        //Iterate the group and qualify it
                        bool isRavenPerpetual = false;
                        bool isRavenSubscription = false;
                        bool isV7 = false;
                        bool isLessThanV7Age = false;
                        var purchaseGroupCustomer = await ct.Customer.AsNoTracking().FirstAsync(z => z.Id == purchaseGroup.First().CustomerId);

                        foreach (var purchase in purchaseGroup)
                        {

                            if (purchase.PGroup == ProductGroup.AyaNova7)
                                isV7 = true;

                            if (purchase.PGroup == ProductGroup.RavenPerpetual)
                                isRavenPerpetual = true;

                            if (purchase.PGroup == ProductGroup.RavenSubscription)
                                isRavenSubscription = true;

                            if (DateTime.UtcNow - purchase.PurchaseDate < PROCESS_V7_AGE)
                                isLessThanV7Age = true; ;
                        }

                        //sanity checks should never be mixed
                        if ((isRavenPerpetual && isV7))
                        {
                            var err = $"SockBotProcessPurchasesIntoLicenses both raven perpetual and v7 in same customer's purchase group First record order number: {purchaseGroup.First().SalesOrderNumber}";
                            //serious issue requires immediate notification
                            await NotifyEventHelper.AddOpsProblemEvent(err);
                            log.LogError(err);
                            continue;
                        }

                        if ((isRavenSubscription && isV7))
                        {
                            var err = $"SockBotProcessPurchasesIntoLicenses both raven subscription and v7 in same customer's purchase group First record order number: {purchaseGroup.First().SalesOrderNumber}";
                            //serious issue requires immediate notification
                            await NotifyEventHelper.AddOpsProblemEvent(err);
                            log.LogError(err);
                            continue;
                        }

                        if ((isRavenPerpetual && isRavenSubscription))
                        {
                            var err = $"SockBotProcessPurchasesIntoLicenses both raven perpetual and raven subscription in same customer's purchase group First record order number: {purchaseGroup.First().SalesOrderNumber}";
                            //serious issue requires immediate notification
                            await NotifyEventHelper.AddOpsProblemEvent(err);
                            log.LogError(err);
                            continue;
                        }

                        //if v7 skip for this iteration to ensure multiple add-on's have all arrived from mycommerce
                        if (isV7 && isLessThanV7Age)
                            continue;

                        License newLicense = new License();
                        //Get last license if any, set up some basic stuff common to all license types
                        var firstPurchase = purchaseGroup.First();
                        var lastLicense = await ct.License.AsNoTracking().OrderByDescending(z => z.Id).FirstOrDefaultAsync(z => z.CustomerId == firstPurchase.CustomerId && z.PGroup == firstPurchase.PGroup);

                        newLicense.CustomerId = firstPurchase.CustomerId;
                        newLicense.Active = false;
                        newLicense.RegTo = firstPurchase.RegTo;

                        //if v7 license then lookup last license for same pgroup for same customer, if none then consider it a new license fresh
                        //if there is one and it's not entirely expired then duplicate and fixup from purchases in this group
                        if (isV7)
                        {
                            newLicense.FetchEmail = purchaseGroupCustomer.EmailAddress;

                            //is there a prior license?
                            if (lastLicense != null)
                            {
                                //copy all the values to the new license
                                newLicense.ExportToXLS = lastLicense.ExportToXLS;
                                newLicense.ExportToXLSExpires = lastLicense.ExportToXLSExpires;
                                newLicense.ImportExportCSVDuplicate = lastLicense.ImportExportCSVDuplicate;
                                newLicense.ImportExportCSVDuplicateExpires = lastLicense.ImportExportCSVDuplicateExpires;
                                newLicense.MaintenanceExpire = lastLicense.MaintenanceExpire;
                                newLicense.MBI = lastLicense.MBI;
                                newLicense.MBIExpires = lastLicense.MBIExpires;
                                newLicense.OLI = lastLicense.OLI;
                                newLicense.OLIExpires = lastLicense.OLIExpires;
                                newLicense.OutlookSchedule = lastLicense.OutlookSchedule;
                                newLicense.OutlookScheduleExpires = lastLicense.OutlookScheduleExpires;
                                newLicense.PTI = lastLicense.PTI;
                                newLicense.PTIExpires = lastLicense.PTIExpires;
                                newLicense.QBI = lastLicense.QBI;
                                newLicense.QBIExpires = lastLicense.QBIExpires;
                                newLicense.QBOI = lastLicense.QBOI;
                                newLicense.QBOIExpires = lastLicense.QBOIExpires;
                                newLicense.QuickNotification = lastLicense.QuickNotification;
                                newLicense.QuickNotificationExpires = lastLicense.QuickNotificationExpires;
                                newLicense.Renewal = true;
                                newLicense.RI = lastLicense.RI;
                                newLicense.RIExpires = lastLicense.RIExpires;
                                newLicense.Tags = lastLicense.Tags;
                                newLicense.Users = lastLicense.Users;
                                newLicense.WBI = lastLicense.WBI;
                                newLicense.WBIExpires = lastLicense.WBIExpires;
                                newLicense.Wiki = lastLicense.Wiki;

                            }
                            //iterate the purchases and update / set the license
                            foreach (var purchase in purchaseGroup)
                            {
                                var product = await ct.Product.AsNoTracking().FirstOrDefaultAsync(z => z.Id == purchase.ProductId);//should *always* exist
                                if (product == null)
                                {
                                    var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has un-matchable product id: {purchase.ProductId}";
                                    //serious issue requires immediate notification
                                    await NotifyEventHelper.AddOpsProblemEvent(err);
                                    log.LogError(err);
                                    continue;
                                }

                                /*
                                id	name	productCode	price	renewPrice
                                1	Key administration	300093112	3500	3500
                                2	Custom work	300151145	0	0
                                3	AyaNova RI 1 year subscription license	300740314	19900	6965
                                4	Single AyaNova schedulable resource 1 year subscription license	300740315	15900	5565
                                5	Single AyaNova Lite 1 year subscription license	300740316	6900	2415
                                6	Up to 5 AyaNova schedulable resource 1 year subscription license	300740317	69500	24325
                                7	Up to 10 AyaNova schedulable resource 1 year subscription license	300740318	119000	41650
                                8	Up to 20 AyaNova schedulable resource 1 year subscription license	300740319	198000	69300
                                9	AyaNova WBI (web browser interface) 1 year subscription license	300740321	9900	3465
                                10	AyaNova MBI (minimal browser interface) 1 year subscription license	300740322	9900	3465
                                11	AyaNova QBI(QuickBooks interface) 1 year subscription license	300740323	9900	3465
                                12	AyaNova PTI(US Peachtree/Sage 50 interface) 1 year subscription license	300740324	9900	3465
                                13	AyaNova OLI(Outlook interface) 1 year subscription license	300740325	9900	3465
                                14	Plug-in Outlook Schedule Export 1 year subscription license	300740326	1900	665
                                15	Plug-in Export to XLS 1 year subscription license	300740327	1900	665
                                16	Plug-in Quick Notification 1 year subscription license	300740328	1900	665
                                17	Plug-in importexport.csv duplicate 1 year subscription license	300740329	1900	665
                                18	Up to 999 AyaNova schedulable resource 1 year subscription license	300741264	15000	5250
                                19	Up to 15 AyaNova schedulable resource 1 year subscription license	300807973	165000	57750
                                20	AyaNova QBOI(QuickBooks Online interface) 1 year subscription license	300784766	12900	4515
                                21	Single AyaNova service techncian perpetual license	301028314	135	100
                                22	Single AyaNova service techncian 1 year maintenance plan - new	301028317	135	100
                                23	Single AyaNova service techncian 1 year maintenance plan - active	301028315	100	100
                                */
                                var dtOneYear = DateTime.UtcNow.AddYears(1);
                                switch (product.VendorCode)
                                {
                                    case "300740314":
                                        newLicense.RI = true;
                                        newLicense.RIExpires = dtOneYear;
                                        break;
                                    case "300740321":
                                        newLicense.WBI = true;
                                        newLicense.WBIExpires = dtOneYear;
                                        break;
                                    case "300740322":
                                        newLicense.MBI = true;
                                        newLicense.MBIExpires = dtOneYear;
                                        break;
                                    case "300740323":
                                        newLicense.QBI = true;
                                        newLicense.QBIExpires = dtOneYear;
                                        break;
                                    case "300740324":
                                        newLicense.PTI = true;
                                        newLicense.PTIExpires = dtOneYear;
                                        break;
                                    case "300740325":
                                        newLicense.OLI = true;
                                        newLicense.OLIExpires = dtOneYear;
                                        break;
                                    case "300740326":
                                        newLicense.OutlookSchedule = true;
                                        newLicense.OutlookScheduleExpires = dtOneYear;
                                        break;
                                    case "300740327":
                                        newLicense.ExportToXLS = true;
                                        newLicense.ExportToXLSExpires = dtOneYear;
                                        break;
                                    case "300740328":
                                        newLicense.QuickNotification = true;
                                        newLicense.QuickNotificationExpires = dtOneYear;
                                        break;
                                    case "300740329":
                                        newLicense.ImportExportCSVDuplicate = true;
                                        newLicense.ImportExportCSVDuplicateExpires = dtOneYear;
                                        break;
                                    case "300784766":
                                        newLicense.QBOI = true;
                                        newLicense.QBOIExpires = dtOneYear;
                                        break;
                                    //USERS
                                    case "300740315":
                                        newLicense.Users = 1;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "300740317":
                                        newLicense.Users = 5;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "300740318":
                                        newLicense.Users = 10;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "300740319":
                                        newLicense.Users = 20;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "300741264":
                                        newLicense.Users = 999;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "300807973":
                                        newLicense.Users = 15;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    default:
                                        var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has product not part of v7 group expected: {product.Name}-{product.VendorCode}";
                                        //serious issue requires immediate notification
                                        await NotifyEventHelper.AddOpsProblemEvent(err);
                                        log.LogError(err);
                                        continue;

                                }//switch product code
                            }//each purchase in purchasegroup

                            //license done ready to save not active so still requires manual intervention but should be substantially ready to send out by here fingers crossed!


                        }//if v7 block
                        else
                        {
                            //it's a RAVEN license
                            //iterate the purchases and update / set the license
                            foreach (var purchase in purchaseGroup)
                            {
                                var product = await ct.Product.AsNoTracking().FirstOrDefaultAsync(z => z.Id == purchase.ProductId);//should *always* exist
                                if (product == null)
                                {
                                    var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has un-matchable product id: {purchase.ProductId}";
                                    //serious issue requires immediate notification
                                    await NotifyEventHelper.AddOpsProblemEvent(err);
                                    log.LogError(err);
                                    continue;
                                }

                                /*
                                    301028317	AyaNova perpetual single user license includes one year maintenance plan 	perpetual	Product	12 months	HD1	Aug 15, 2022, 9:07 PM
                                    301028467	AyaNova subscription one user monthly	subscriptionmonthly	Product	monthly	HD1	Aug 18, 2022, 1:21 AM
                                    301028468	AyaNova subscription one user yearly	subscriptionyearly	Product	12 months	HD1	Aug 18, 2022, 1:25 AM	
                                    301033167	AyaNova subscription additional 250 customer users monthly	250customerusersmonthly	Product	monthly	HD1	Oct 6, 2022, 12:56 AM
                                    301033168	AyaNova subscription additional 250 customer users yearly	250customerusersyearly	Product	12 months	HD1	Oct 6, 2022, 12:59 AM
                                */
                                //RAVEN licenses have one week padding to be on the safe side
                                var dtOneYear = DateTime.UtcNow.AddYears(1).AddDays(7);
                                var dtOneMonth = DateTime.UtcNow.AddMonths(1).AddDays(7);
                                switch (product.VendorCode)
                                {

                                    case "301028317"://perpetual
                                        newLicense.Users = purchase.Quantity;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        break;
                                    case "301028467"://subscription monthly
                                        newLicense.Users = purchase.Quantity;
                                        newLicense.MaintenanceExpire = dtOneMonth;
                                        //FUTURE: for now subscriptions all 20gb if ever add ability to go higher max data with product code etc then remove this
                                        newLicense.MaxDataGB = 20;
                                        break;
                                    case "301028468"://subscription yearly
                                        newLicense.Users = purchase.Quantity;
                                        newLicense.MaintenanceExpire = dtOneYear;
                                        //FUTURE: for now subscriptions all 20gb if ever add ability to go higher max data with product code etc then remove this
                                        newLicense.MaxDataGB = 20;
                                        break;
                                    case "301033167"://Customer users monthly price
                                    case "301033168"://Customer users yearly price
                                        newLicense.CustomerUsers = purchase.Quantity;
                                        break;
                                    default:
                                        var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has product not part of RAVEN products expected: {product.Name}-{product.VendorCode}";
                                        //serious issue requires immediate notification
                                        await NotifyEventHelper.AddOpsProblemEvent(err);
                                        log.LogError(err);
                                        continue;

                                }//switch product code
                            }//each purchase in purchasegroup

                        }

                        //we have a new savable license at this point
                        if (newLicense != null)
                        {
                            LicenseBiz lbiz = LicenseBiz.GetBiz(ct);
                            newLicense = await lbiz.CreateAsync(newLicense);
                            if (newLicense == null)
                            {
                                //did not save, throw an error
                                throw new System.ApplicationException($"Error creating license from purchases: {lbiz.GetErrorsAsString()}");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    var err = "SockBotProcessPurchasesIntoLicenses exepected exception error running job";
                    //serious issue requires immediate notification
                    await NotifyEventHelper.AddOpsProblemEvent(err, ex);
                    log.LogError(ex, err);
                }

            }
        }






        /////////////////////////////////////////////////////////////////////

    }//eoc


}//eons

