using System;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using rockfishCore.Models;

namespace rockfishCore.Util
{
    //Key generator controller
    public static class RfSchema
    {
        private static rockfishContext ctx;

        /////////////////////////////////////////////////////////////////
        /////////// CHANGE THIS ON NEW SCHEMA UPDATE ////////////////////
        public const int DESIRED_SCHEMA_LEVEL = 15;
        /////////////////////////////////////////////////////////////////


        static int startingSchema = -1;
        static int currentSchema = -1;

        //check and update schema
        public static void CheckAndUpdate(rockfishContext context)
        {
            ctx = context;
            bool rfSetExists = false;

            //update schema here?           
            using (var command = ctx.Database.GetDbConnection().CreateCommand())
            {
                //first of all, do we have a schema table yet (v0?)
                command.CommandText = "SELECT name FROM sqlite_master WHERE type='table' AND name='rfset';";
                ctx.Database.OpenConnection();
                using (var result = command.ExecuteReader())
                {
                    if (result.HasRows)
                    {
                        rfSetExists = true;
                    }
                    ctx.Database.CloseConnection();
                }
            }
            //Create schema table (v1)
            if (!rfSetExists)
            {
                //nope, no schema table, add it now and set to v1
                using (var cmCreateRfSet = ctx.Database.GetDbConnection().CreateCommand())
                {
                    context.Database.OpenConnection();
                    //first of all, do we have a schema table yet (v0?)
                    cmCreateRfSet.CommandText = "CREATE TABLE rfset (id INTEGER PRIMARY KEY, schema INTEGER NOT NULL);";
                    cmCreateRfSet.ExecuteNonQuery();

                    cmCreateRfSet.CommandText = "insert into rfset (schema) values (1);";
                    cmCreateRfSet.ExecuteNonQuery();

                    context.Database.CloseConnection();
                    startingSchema = 1;
                    currentSchema = 1;
                }
            }
            else
            {
                //get current schema level
                using (var cm = ctx.Database.GetDbConnection().CreateCommand())
                {
                    cm.CommandText = "SELECT schema FROM rfset WHERE id=1;";
                    ctx.Database.OpenConnection();
                    using (var result = cm.ExecuteReader())
                    {
                        if (result.HasRows)
                        {
                            result.Read();
                            currentSchema = startingSchema = result.GetInt32(0);
                            ctx.Database.CloseConnection();
                        }
                        else
                        {
                            ctx.Database.CloseConnection();
                            throw new System.Exception("rockfish->RfSchema->CheckAndUpdate: Error reading schema version");
                        }
                    }
                }
            }

            //Bail early no update?
            if (currentSchema == DESIRED_SCHEMA_LEVEL)
                return;



            //************* SCHEMA UPDATES ******************

            //////////////////////////////////////////////////
            //schema 2 case 3283
            if (currentSchema < 2)
            {
                //add renewal flag to purchase
                exec("alter table purchase add renewNoticeSent boolean default 0 NOT NULL CHECK (renewNoticeSent IN (0,1))");
                //Add product table with prices
                exec("CREATE TABLE product (id INTEGER PRIMARY KEY, name text not null, productCode text, price integer, renewPrice integer )");
                currentSchema = 2;
                setSchemaLevel(currentSchema);
            }

            //////////////////////////////////////////////////
            //schema 3 case 3283
            if (currentSchema < 3)
            {
                //add products current as of 2017-July-18
                exec("insert into product (name, productCode, price, renewPrice) values ('Key administration','300093112',3500, 3500);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Custom work','300151145',0, 0);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova RI sub (old / unused?)','300740314',19900, 6965);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova schedulable resource 1 year subscription license','300740315',15900, 5565);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova Lite 1 year subscription license','300740316',6900, 2415);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Up to 5 AyaNova schedulable resource 1 year subscription license','300740317', 69500, 24325);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Up to 10 AyaNova schedulable resource 1 year subscription license','300740318',119000, 41650);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Up to 20 AyaNova schedulable resource 1 year subscription license','300740319',198000, 69300);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova WBI (web browser interface) 1 year subscription license','300740321',9900, 3465);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova MBI (minimal browser interface) 1 year subscription license','300740322', 9900, 3465);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova QBI(QuickBooks interface) 1 year subscription license','300740323',9900, 3465);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova PTI(US Peachtree/Sage 50 interface) 1 year subscription license','300740324',9900, 3465);");
                exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova OLI(Outlook interface) 1 year subscription license','300740325',9900, 3465);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Outlook Schedule Export 1 year subscription license','300740326',1900, 665);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Export to XLS 1 year subscription license','300740327',1900, 665);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Quick Notification 1 year subscription license','300740328',1900, 665);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in importexport.csv duplicate 1 year subscription license','300740329',1900, 665);");
                exec("insert into product (name, productCode, price, renewPrice) values ('Up to 999 AyaNova schedulable resource 1 year subscription license','300741264',15000, 5250);");

                currentSchema = 3;
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 4 case 3283
            if (currentSchema < 4)
            {
                //Add template table to store email and other templates
                exec("CREATE TABLE texttemplate (id INTEGER PRIMARY KEY, name text not null, template text)");
                currentSchema = 4;
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 5 case 3253
            if (currentSchema < 5)
            {
                exec("alter table customer add active boolean default 1 NOT NULL CHECK (active IN (0,1))");
                currentSchema = 5;
                setSchemaLevel(currentSchema);
            }



            //////////////////////////////////////////////////
            //schema 6 case 3308
            if (currentSchema < 6)
            {

                exec("CREATE TABLE rfcaseproject (id INTEGER PRIMARY KEY, name text not null)");

                exec("CREATE TABLE rfcase (id INTEGER PRIMARY KEY, title text not null, rfcaseprojectid integer not null, " +
                "priority integer default 3 NOT NULL CHECK (priority IN (1,2,3,4,5)), notes text, dtcreated integer, dtclosed integer, " +
                "releaseversion text, releasenotes text, " +
                "FOREIGN KEY (rfcaseprojectid) REFERENCES rfcaseproject(id))");

                exec("CREATE TABLE rfcaseblob (id INTEGER PRIMARY KEY, rfcaseid integer not null, name text not null, file blob not null, " +
               "FOREIGN KEY (rfcaseid) REFERENCES rfcase(id) ON DELETE CASCADE  )");

                currentSchema = 6;
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 7 case 3308
            if (currentSchema < 7)
            {

                //empty any prior import data
                exec("delete from rfcaseblob");
                exec("delete from rfcase");
                exec("delete from rfcaseproject");

                //Trigger import of all fogbugz cases into rockfish
                Util.FBImporter.Import(ctx);

                //now get rid of the delete records
                exec("delete from rfcase where title='deleted from FogBugz'");

                currentSchema = 7;//<<-------------------- TESTING, CHANGE TO 7 BEFORE PRODUCTION
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 8 
            if (currentSchema < 8)
            {
                exec("alter table user add dlkey text");
                currentSchema = 8;
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 9
            if (currentSchema < 9)
            {
                exec("alter table user add dlkeyexp integer");
                currentSchema = 9;
                setSchemaLevel(currentSchema);
            }



            //////////////////////////////////////////////////
            //schema 10 case 3233
            if (currentSchema < 10)
            {

                exec("CREATE TABLE license (" +
                "id INTEGER PRIMARY KEY, dtcreated integer not null, customerid integer not null, regto text not null, key text not null, code text not null, email text not null, " +
                "fetchfrom text, dtfetched integer, fetched boolean default 0 NOT NULL CHECK (fetched IN (0,1))" +
                ")");

                currentSchema = 10;
                setSchemaLevel(currentSchema);
            }



            //////////////////////////////////////////////////
            //schema 11 case 3550
            if (currentSchema < 11)
            {
                //add 15 level product code 
                exec("insert into product (name, productCode, price, renewPrice) values ('Up to 15 AyaNova schedulable resource 1 year subscription license','300807973',165000, 57750);");
                currentSchema = 11;
                setSchemaLevel(currentSchema);
            }

            //////////////////////////////////////////////////
            //schema 12
            if (currentSchema < 12)
            {
                exec("alter table customer add supportEmail text");
                exec("alter table customer add adminEmail text");
                currentSchema = 12;
                setSchemaLevel(currentSchema);
            }

            //////////////////////////////////////////////////
            //schema 13
            if (currentSchema < 13)
            {
                //Put all the purchase emails into the customer adminEmail field as CSV
                //These will get all notification types
                foreach (var purchase in ctx.Purchase.AsNoTracking())
                {
                    if (!string.IsNullOrWhiteSpace(purchase.Email))
                    {
                        var cust = ctx.Customer.SingleOrDefault(m => m.Id == purchase.CustomerId);
                        if (cust == null)
                        {
                            throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (purchases) CUSTOMER {purchase.CustomerId.ToString()} not found!!");
                        }

                        var purchaseEmails = purchase.Email.Split(",");
                        foreach (var email in purchaseEmails)
                        {
                            Util.CustomerUtils.AddAdminEmailIfNotPresent(cust, email);
                        }
                        ctx.SaveChanges();
                    }
                }

                // //Put all the contact emails into the customer adminEmail field and the support field as CSV
                // //These will get all notification types
                // foreach (var contact in ctx.Contact.AsNoTracking())
                // {
                //     if (!string.IsNullOrWhiteSpace(contact.Email))
                //     {
                //         var cust = ctx.Customer.SingleOrDefault(m => m.Id == contact.CustomerId);
                //         if (cust == null)
                //         {
                //             throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (contacts) CUSTOMER {contact.CustomerId.ToString()} not found!!");
                //         }

                //         var contactEmails = contact.Email.Split(",");
                //         foreach (var email in contactEmails)
                //         {
                //             Util.CustomerUtils.AddAdminEmailIfNotPresent(cust, email);
                //         }
                //         ctx.SaveChanges();
                //     }
                // }


                // //Put all the incident emails into the customer supportEmail field unless already in teh admin field or support field  field and the support field as CSV
                // //These will get only support related (updates/bug reports) notification types
                // foreach (var incident in ctx.Incident.AsNoTracking())
                // {
                //     if (!string.IsNullOrWhiteSpace(incident.Email))
                //     {
                //         var cust = ctx.Customer.SingleOrDefault(m => m.Id == incident.CustomerId);
                //         if (cust == null)
                //         {
                //             throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (incidents) CUSTOMER {incident.CustomerId.ToString()} not found!!");
                //         }

                //         var incidentEmails = incident.Email.Split(",");
                //         foreach (var email in incidentEmails)
                //         {

                //             //See if incident email is already in adminEmail field:
                //             if (cust.AdminEmail != null && cust.AdminEmail.ToLowerInvariant().Contains(email.Trim().ToLowerInvariant()))
                //             {
                //                 continue;//skip this one, it's already there
                //             }

                //             //It's not in the adminEmail field already so add it to the supportEmail
                //             //field (assumption: all incidents are support related and particularly ones that are not already in admin)
                //             Util.CustomerUtils.AddSupportEmailIfNotPresent(cust, email);
                //         }
                //         ctx.SaveChanges();
                //     }
                // }


                //NOTE: NOTIFICATION AND TRIAL tables have emails but they are dupes, empty or not required based on actual data so not going to import them

                currentSchema = 13;
                setSchemaLevel(currentSchema);
            }

            //////////////////////////////////////////////////
            //schema 14
            if (currentSchema < 14)
            {
                exec("update license set fetchfrom = 'redacted'");
                currentSchema = 14;
                setSchemaLevel(currentSchema);
            }


            //////////////////////////////////////////////////
            //schema 15
            if (currentSchema < 15)
            {
                exec("drop table contact");
                exec("drop table incident");
                exec("drop table notification");
                exec("drop table trial");
                currentSchema = 15;
                setSchemaLevel(currentSchema);
            }

            //*************************************************************************************


        }//eofunction



        private static void setSchemaLevel(int nCurrentSchema)
        {
            exec("UPDATE RFSET SET schema=" + nCurrentSchema.ToString());
        }

        //execute command query
        private static void exec(string q)
        {
            using (var cmCreateRfSet = ctx.Database.GetDbConnection().CreateCommand())
            {
                ctx.Database.OpenConnection();
                cmCreateRfSet.CommandText = q;
                cmCreateRfSet.ExecuteNonQuery();
                ctx.Database.CloseConnection();
            }
        }

        //eoclass
    }
    //eons
}