using Foresight.Data;
using Foresight.Fleet.Services.AssetHealth;
using Foresight.ServiceModel;
using IronIntel.Contractor.Machines;
using IronIntel.Contractor.Maintenance;
using IronIntel.Contractor.Users;
using IronIntel.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace IronIntel.Contractor.Site.Maintenance
{
    public class AlertsBasePage : ContractorBasePage
    {
        protected void ProcessRequest(string method)
        {
            object result = null;
            try
            {
                string methodName = Request.Params["MethodName"];
                if (methodName != null)
                {
                    switch (methodName.ToUpper())
                    {
                        case "GETALERTS":
                            result = GetAlerts();
                            break;
                        case "GETMACHINEALERTS":
                            result = GetMachineAlerts();
                            break;
                        case "SAVEACKNOWLEDGEALERT":
                            result = SaveAcknowledgeAlert();
                            break;
                        case "ASSIGNEDALERTSTOWORKORDER":
                            result = AssignedAlertsToWorkOrder();
                            break;
                        case "GETALERTSBYWORKORDER":
                            result = GetAlertsByWorkOrder();
                            break;
                        case "GETALERTSLISENCE":
                            result = GetAlertsLisence();
                            break;
                        case "GETWORKORDERALERTS":
                            result = GetWorkOrderAlerts();
                            break;
                        case "GETASSETALERTS":
                            result = GetAssetAlerts();
                            break;
                        case "GETASSETGROUPS":
                            result = GetAssetGroups();
                            break;
                        case "GETALERTTYPES":
                            result = GetAlertTypes();
                            break;
                        case "GETACKNOWLEDGEDALERTS":
                            result = GetAcknowledgedAlerts();
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                SystemParams.WriteLog("error", "AlertsBasePage", ex.Message, ex.ToString());
                throw ex;
            }
            string json = JsonConvert.SerializeObject(result);
            Response.Write(json);
            Response.End();
        }

        private object GetAlerts()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Context.Request.Params["ClientData"];
                    AlertQueryParams alertparam = JsonConvert.DeserializeObject<AlertQueryParams>(clientdata);
                    DateTime beginDate = Helper.DBMinDateTime;
                    DateTime endDate = DateTime.MaxValue;
                    if (!DateTime.TryParse(alertparam.BeginDate, out beginDate))
                        beginDate = Helper.DBMinDateTime;
                    //else
                    //    beginDate = beginDate.ToUniversalTime();
                    if (!DateTime.TryParse(alertparam.EndDate, out endDate))
                        endDate = DateTime.MaxValue;
                    else
                        endDate = endDate.Date.AddDays(1).AddSeconds(-1);

                    int assigned = -1;
                    int completed = -1;
                    if (alertparam.AlertStatus != null && alertparam.AlertStatus.Length > 0)
                    {
                        if (alertparam.AlertStatus.Contains("Unassigned") && !alertparam.AlertStatus.Contains("Assigned"))
                            assigned = 0;
                        if (!alertparam.AlertStatus.Contains("Unassigned") && alertparam.AlertStatus.Contains("Assigned"))
                            assigned = 1;

                        if (alertparam.AlertStatus.Contains("Completed") && !alertparam.AlertStatus.Contains("Uncompleted"))
                            assigned = 1;
                        if (!alertparam.AlertStatus.Contains("Completed") && alertparam.AlertStatus.Contains("Uncompleted"))
                            assigned = 0;
                    }
                    AssetAlertGridViewItem[] assetalerts = CreateClient<WorkOrderClient>().GetAssetAlertGridViewItems(SystemParams.CompanyID, beginDate, endDate, alertparam.AlertTypes, alertparam.AssetGroups, assigned, completed, alertparam.SearchText, session.User.UID);
                    if (assetalerts == null || assetalerts.Length == 0)
                        return new AlertInfo[0];
                    List<AlertInfo> list = new List<AlertInfo>();
                    foreach (AssetAlertGridViewItem item in assetalerts)
                    {
                        AlertInfo ai = ConvertAlertObj(item);
                        ai.AlertTime_UTC = item.LastAlertLocalTime;
                        list.Add(ai);
                    }
                    return list.ToArray();
                }
                else
                    return new AlertInfo[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAlerts", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private object GetMachineAlerts()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Context.Request.Params["ClientData"];
                    AlertQueryParams alertparam = JsonConvert.DeserializeObject<AlertQueryParams>(clientdata);
                    DateTime beginDate = Helper.DBMinDateTime;
                    DateTime endDate = DateTime.MaxValue;
                    if (!DateTime.TryParse(alertparam.BeginDate, out beginDate))
                        beginDate = Helper.DBMinDateTime;
                    //else
                    //    beginDate = beginDate.ToUniversalTime();
                    if (!DateTime.TryParse(alertparam.EndDate, out endDate))
                        endDate = DateTime.MaxValue;
                    else
                        endDate = endDate.Date.AddDays(1).AddSeconds(-1);

                    int assigned = -1;
                    int completed = -1;
                    if (alertparam.AlertStatus != null && alertparam.AlertStatus.Length > 0)
                    {
                        if (alertparam.AlertStatus.Contains("Unassigned") && !alertparam.AlertStatus.Contains("Assigned"))
                            assigned = 0;
                        if (!alertparam.AlertStatus.Contains("Unassigned") && alertparam.AlertStatus.Contains("Assigned"))
                            assigned = 1;

                        if (alertparam.AlertStatus.Contains("Completed") && !alertparam.AlertStatus.Contains("Uncompleted"))
                            assigned = 1;
                        if (!alertparam.AlertStatus.Contains("Completed") && alertparam.AlertStatus.Contains("Uncompleted"))
                            assigned = 0;
                    }

                    AssetAlertGridViewItem[] assetalerts = CreateClient<WorkOrderClient>().GetAssetAlertGridViewItems(SystemParams.CompanyID, beginDate, endDate, alertparam.AlertTypes, alertparam.AssetGroups, assigned, completed, alertparam.SearchText, session.User.UID);

                    if (assetalerts == null || assetalerts.Length == 0)
                        return new MachineInfoForAlert[0];

                    List<MachineInfoForAlert> machinealerts = new List<MachineInfoForAlert>();
                    foreach (AssetAlertGridViewItem item in assetalerts)
                    {
                        AlertInfo ai = ConvertAlertObj(item);
                        MachineInfoForAlert mi = machinealerts.FirstOrDefault((i) => i.MachineID == ai.MachineID);
                        if (mi == null)
                        {
                            mi = new MachineInfoForAlert();
                            mi.MachineID = ai.MachineID;
                            mi.MachineName = ai.MachineName;
                            mi.VIN = ai.VIN;
                            mi.Make = ai.Make;
                            mi.Model = ai.Model;
                            mi.EngineHours = ai.CurrentHours;
                            mi.OpenWorkOrders = ai.OpenWorkOrderCount;

                            machinealerts.Add(mi);
                        }
                        mi.Alerts.Add(ai);

                        int count = ai.RepeatedAlerts.Count + 1;

                        if (ai.AlertType == "Preventative Maintenance"
                          || ai.AlertType == "PM_ALERT" || ai.AlertType == "TBM_ALERT" || ai.AlertType == "HM_ALERT"
                          || ai.AlertType == "RDM_ALERT" || ai.AlertType == "ADM_ALERT")
                            mi.PMAlertCount += count;
                        else if (INSPECT.Contains(ai.AlertType, StringComparer.OrdinalIgnoreCase))
                            mi.InspectAlertCount += count;
                        else
                            mi.DTCAlertCount += count;
                        if (ai.AlertTime_UTC > mi.LatestAlertDateTime)
                            mi.LatestAlertDateTime = ai.AlertTime_UTC;
                    }

                    return machinealerts.ToArray();
                }
                else
                    return new MachineInfoForAlert[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAlerts", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private AlertInfo ConvertAlertObj(AssetAlertGridViewItem item)
        {
            AlertInfo ai = new AlertInfo();
            ai.AlertID = item.ID;
            ai.WorkOrderID = item.WorkOrderId;
            ai.WorkOrderStatus = item.WorkOrderStatus;
            ai.AlertType = item.AlertType;
            ai.AlertTime_UTC = item.LastAlertTime;
            ai.Completed = item.Completed;
            ai.MachineID = item.AssetID;
            //ai.ModelID = item.ModelName;
            ai.Model = item.ModelName;
            //ai.MakeID = item.MakeName;
            ai.Make = item.MakeName;
            ai.VIN = item.VIN;
            ai.MachineName = item.AssetName;
            ai.EngineHours = item.EngineHours;
            ai.CurrentHours = item.CurrentEngineHours;
            ai.Description = item.Description;
            ai.ServiceDescription = item.ServiceDescription;
            ai.RepeatedAlerts = item.RepeatedAlerts;
            ai.AlertCount = item.RepeatedAlerts.Count + 1;
            ai.OpenWorkOrderCount = item.OpenWorkOrderCount;

            return ai;
        }

        private object GetAcknowledgedAlerts()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Context.Request.Params["ClientData"];
                    AlertQueryParams alertparam = JsonConvert.DeserializeObject<AlertQueryParams>(clientdata);
                    DateTime beginDate = Helper.DBMinDateTime;
                    DateTime endDate = DateTime.MaxValue;
                    if (!DateTime.TryParse(alertparam.BeginDate, out beginDate))
                        beginDate = Helper.DBMinDateTime;
                    //else
                    //    beginDate = beginDate.ToUniversalTime();
                    if (!DateTime.TryParse(alertparam.EndDate, out endDate))
                        endDate = DateTime.MaxValue;
                    else
                        endDate = endDate.Date.AddDays(1).AddSeconds(-1);

                    alertparam.AlertStatus = new string[0];
                    AlertManager am = new AlertManager(SystemParams.DataDbConnectionString);
                    AlertInfo[] alerts = am.SearchAcknowledgedAlerts(session.SessionID, alertparam.SearchText, alertparam.AlertStatus, alertparam.AlertTypes, alertparam.AssetGroups, beginDate, endDate, session.User.UID);
                    if (alerts == null)
                        return new AlertInfo[0];
                    return alerts.ToArray();
                }
                else
                    return new AlertInfo[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAcknowledgedAlerts", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private object GetAlertsLisence()
        {
            try
            {
                AlertsLisenceItem result = new AlertsLisenceItem();
                if (GetCurrentLoginSession() != null)
                {
                    LicenseInfo license = SystemParams.GetLicense();
                    if (license != null && license.Items.Count > 0)
                    {
                        var woitem = license.Items.FirstOrDefault(m => m.Key == "WorkOrder");
                        if (woitem != null && Helper.IsTrue(woitem.Value))
                            result.WorkOrder = true;
                    }
                    result.AcknowledgingAlerts = Helper.IsTrue(SystemParams.GetStringParam("AcknowledgingAlerts"));
                }
                return result;
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAlertsLisence", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private string SaveAcknowledgeAlert()
        {
            try
            {
                Services.Users.LoginSession se = GetCurrentLoginSession();
                if (se != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var ids = HttpUtility.HtmlDecode(clientdata[0]);
                    var acknowledgmentcomment = HttpUtility.HtmlDecode(clientdata[1]);
                    long[] list = JsonConvert.DeserializeObject<long[]>(ids);
                    AlertManager am = new AlertManager(SystemParams.DataDbConnectionString);
                    am.AcknowledgeAlert(se.User.UID, list, acknowledgmentcomment);
                    return "OK";
                }
                else
                    return "Failed";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private string AssignedAlertsToWorkOrder()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var id = HttpUtility.HtmlDecode(clientdata[0]);
                    var ids = HttpUtility.HtmlDecode(clientdata[1]);
                    long workorderid = Convert.ToInt64(id);
                    long[] alertids = JsonConvert.DeserializeObject<long[]>(ids);
                    if (alertids != null && alertids.Length == 0)
                        alertids = null;
                    AlertManager am = new AlertManager(SystemParams.DataDbConnectionString);
                    am.AssignedAlertsToWorkOrder(workorderid, alertids);
                    return "OK";
                }
                else
                    return "Failed";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetAlertsByWorkOrder()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var woid = Request.Form["ClientData"];
                    long workorderid = Convert.ToInt64(woid);
                    AlertManager am = new AlertManager(SystemParams.DataDbConnectionString);
                    AlertInfo[] alerts = am.GetAlertsByWorkOrder(workorderid);
                    if (alerts == null)
                        return new AlertInfo[0];
                    return alerts;
                }
                else
                    return new AlertInfo[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAlertsByWorkOrder", ex.Message, ex.ToString());
                return ex.Message;
            }
        }
        private object GetWorkOrderAlerts()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"];

                    long workorderid = 0;
                    long.TryParse(clientdata, out workorderid);

                    AssetAlertItem[] alerts = CreateClient<WorkOrderClient>().GetAssignedAlerts(SystemParams.CompanyID, workorderid);

                    AlertItems items = new AlertItems();
                    if (alerts != null)
                    {
                        var dtcalerts = new List<AlertInfo>();
                        var pmaalerts = new List<AlertInfo>();
                        var inspectalerts = new List<AlertInfo>();
                        var oilalerts = new List<AlertInfo>();
                        foreach (AssetAlertItem alertitem in alerts.OrderByDescending(ai => ai.AlertTime))
                        {
                            List<AlertInfo> tempList = null;
                            if (alertitem.Category == AssetAlertCategory.PMAlert)
                                tempList = pmaalerts;
                            else if (alertitem.Category == AssetAlertCategory.InspectAlert)
                                tempList = inspectalerts;
                            else if (alertitem.Category == AssetAlertCategory.OilSampleAlert)
                                tempList = oilalerts;
                            else
                                tempList = dtcalerts;

                            var existalert = tempList.FirstOrDefault((ai) => ai.Description == alertitem.Description);
                            if (existalert != null)
                            {
                                existalert.AlertCount++;
                                if (existalert.RepeatedAlerts == null)
                                    existalert.RepeatedAlerts = new List<long>();
                                existalert.RepeatedAlerts.Add(alertitem.ID);
                            }
                            else
                            {
                                var a = ConvertAlert(alertitem);
                                a.AlertCount = 1;
                                tempList.Add(a);
                            }
                        }
                        items.DTCAlerts = dtcalerts.ToArray();
                        items.PMAlerts = pmaalerts.ToArray();
                        items.InspectAlerts = inspectalerts.ToArray();
                        items.OilAlerts = oilalerts.ToArray();
                    }
                    return items;
                }
                else
                    return new AlertInfo[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetWorkOrderAlerts", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private object GetAssetAlerts()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var mid = HttpUtility.HtmlDecode(clientdata[0]);
                    var ids = HttpUtility.HtmlDecode(clientdata[1]);

                    long machineid = 0;
                    long.TryParse(mid, out machineid);

                    long[] alertids = JsonConvert.DeserializeObject<long[]>(ids);

                    AssetAlertGridViewItem[] alerts = CreateClient<WorkOrderClient>().GetAssetAlertGridViewItemsByAsset(SystemParams.CompanyID, machineid, Helper.DBMinDateTime, DateTime.MaxValue, null, -1, -1, "");
                    AlertItems items = new AlertItems();
                    if (alerts != null)
                    {
                        var dtcalerts = new List<AlertInfo>();
                        var pmaalerts = new List<AlertInfo>();
                        var inspectalerts = new List<AlertInfo>();
                        var oilalerts = new List<AlertInfo>();
                        foreach (AssetAlertGridViewItem alertitem in alerts.OrderByDescending(ai => ai.AlertTime))
                        {
                            if (alertids != null && alertids.Length > 0 && !alertids.Contains(alertitem.ID))
                                continue;
                            if (alertitem.Completed || alertitem.Acknowledged || alertitem.WorkOrderId > 0)
                                continue;

                            List<AlertInfo> tempList = null;
                            var category = DetermineAlertCategory(alertitem.AlertType);
                            if (category == AssetAlertCategory.PMAlert)
                                tempList = pmaalerts;
                            else if (category == AssetAlertCategory.InspectAlert)
                                tempList = inspectalerts;
                            else if (category == AssetAlertCategory.OilSampleAlert)
                                tempList = oilalerts;
                            else
                                tempList = dtcalerts;

                            var a = ConvertAlertObj(alertitem);
                            a.RepeatedAlerts = alertitem.RepeatedAlerts;
                            a.AlertCount = alertitem.RepeatedAlerts.Count + 1;
                            tempList.Add(a);
                        }
                        items.DTCAlerts = dtcalerts.ToArray();
                        items.PMAlerts = pmaalerts.ToArray();
                        items.InspectAlerts = inspectalerts.ToArray();
                        items.OilAlerts = oilalerts.ToArray();
                    }
                    return items;
                }
                else
                    return new AlertInfo[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAssetAlerts", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private static readonly string[] PMALERTS = new string[] { "Preventative Maintenance" };
        private static readonly string[] INSPECT = new string[] { "Red-Inspect", "Yellow-Inspect", "Green-Inspect", "Info-Inspect" };
        private static readonly string[] OILSAMPLE = new string[] { "Oil Sample Result" };
        private static AssetAlertCategory DetermineAlertCategory(string alerttype)
        {
            if (PMALERTS.Contains(alerttype, StringComparer.OrdinalIgnoreCase))
            {
                return AssetAlertCategory.PMAlert;
            }
            if (INSPECT.Contains(alerttype, StringComparer.OrdinalIgnoreCase))
            {
                return AssetAlertCategory.InspectAlert;
            }
            if (OILSAMPLE.Contains(alerttype, StringComparer.OrdinalIgnoreCase))
            {
                return AssetAlertCategory.OilSampleAlert;
            }

            return AssetAlertCategory.DTCAlert;
        }

        private object GetAssetGroups()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var groups = MachineManagement.GetMachineGroupsByUser(session.User.UID, null);
                    List<StringKeyValue> list = new List<StringKeyValue>();
                    foreach (var gp in groups)
                    {
                        StringKeyValue kv = new StringKeyValue();
                        kv.Key = gp.GroupID;
                        kv.Value = gp.GroupName;
                        list.Add(kv);
                    }

                    return list.OrderBy((m) => m.Value).ToArray();
                }
                else
                    return new StringKeyValue[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAssetGroups", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private object GetAlertTypes()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    AlertManager am = new AlertManager(SystemParams.DataDbConnectionString);
                    return am.GetAlertTypes(); ;
                }
                else
                    return new StringKeyValue[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAlertTypes", ex.Message, ex.ToString());
                return ex.Message;
            }
        }


        private AlertInfo ConvertAlert(AssetAlertItem alertitem)
        {
            AlertInfo ai = new AlertInfo();
            ai.AlertID = alertitem.ID;
            ai.MachineID = alertitem.AssetID;
            ai.AlertType = alertitem.AlertType;
            ai.Description = alertitem.Description;
            ai.AlertTime_UTC = alertitem.AlertTime;
            ai.EngineHours = alertitem.EngineHours;

            return ai;
        }
    }
    public class AlertItems
    {
        public AlertInfo[] DTCAlerts { get; set; }
        public AlertInfo[] PMAlerts { get; set; }
        public AlertInfo[] InspectAlerts { get; set; }
        public AlertInfo[] OilAlerts { get; set; }
    }
    public class AlertQueryParams
    {
        public string SearchText { get; set; }
        public string[] AlertStatus { get; set; }
        public string[] AssetGroups { get; set; }
        public string[] AlertTypes { get; set; }
        public string BeginDate { get; set; }
        public string EndDate { get; set; }
    }

    public class AlertsLisenceItem
    {
        public bool WorkOrder = false;
        public bool AcknowledgingAlerts = false;
    }
}
