using Foresight.Fleet.Services.Asset;
using Foresight.Fleet.Services.JobSite;
using Foresight.ServiceModel;
using IronIntel.Contractor.Contact;
using IronIntel.Contractor.JobSites;
using IronIntel.Contractor.Machines;
using IronIntel.Contractor.Maintenance;
using IronIntel.Contractor.MapView;
using IronIntel.Contractor.Users;
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
{
    public class UserManageBasePage : ContractorBasePage
    {
        protected void ProcessRequest(string methodName)
        {
            object result = null;
            try
            {
                if (methodName != null)
                {
                    switch (methodName.ToUpper())
                    {
                        case "GETUSERS":
                            result = GetUsers();
                            break;
                        case "ADDUSER":
                            result = SaveUser(true);
                            break;
                        case "EDITUSER":
                            result = SaveUser(false);
                            break;
                        case "DELETEUSER":
                            result = DeleteUser();
                            break;
                        case "RESETPASSWORD":
                            result = ResetPassword();
                            break;
                        case "GETUSERMACHINEGROUP":
                            result = GetUserMachineGroup();
                            break;
                        case "SAVEUSERMACHINEGROUP":
                            result = SaveUserMachineGroup();
                            break;
                        case "GETUSERINFO":
                            result = GetUserInfo();
                            break;
                        case "GETALLGROUPS":
                            result = GetAllGroups();
                            break;
                        case "GETGROUPSBYUSER":
                            result = GetGroupsByUser();
                            break;
                        case "GETSELECTEDMACHINES":
                            result = GetSelectedMachines();
                            break;
                        case "GETSELECTEDASSETS":
                            result = GetSelectedAssets();
                            break;
                        case "ASSIGNASSETSTOUSER":
                            result = AssignAssetsToUser();
                            break;
                        case "REMOVEASSIGNEDASSETSFROMUSER":
                            result = RemoveAssignedAssetsFromUser();
                            break;
                        case "SAVECONTACTMACHINES":
                            result = SaveContactMachines();
                            break;
                        case "GETJOBSITELIST":
                            result = GetJobsiteList();
                            break;
                        case "GETSELECTEDJOBSITES":
                            result = GetSelectedJobsites();
                            break;
                        case "SAVECONTACTJOBSITES":
                            result = SaveContactJobsites();
                            break;
                        case "GETMACHINETYPES":
                            Machines.MachineManagement.RefreshMachineTypes();
                            result = MachineManagement.GetMachineTypes().OrderBy(m => m.Name).Select(t => new
                            {
                                ID = t.ID,
                                Name = t.Name
                            });
                            break;
                        case "GETMACHINELIST":
                            result = GetMachineList();
                            break;
                        case "GETAVAILABLEFEATURES":
                            result = GetAvailableFeatures();
                            break;
                        case "GETFEATURESDEFINEDONUSER":
                            result = GetFeaturesDefinedOnUser();
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                SystemParams.WriteLog("error", "ContactBasePage", ex.Message, ex.ToString());
                throw ex;
            }
            string json = JsonConvert.SerializeObject(result);
            Response.Write(json);
            Response.End();
        }

        #region Security

        private object GetAvailableFeatures()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var client = CreateClient<Foresight.Fleet.Services.User.PermissionProvider>();
                    Foresight.Fleet.Services.User.Feature[] features = client.GetAvailableFeatures(SystemParams.CompanyID);
                    if (features == null || features.Length == 0)
                        return new FeatureModuleItem[0];

                    List<FeatureModuleItem> list = new List<FeatureModuleItem>();
                    foreach (var feature in features)
                    {
                        FeatureModuleItem fmi = list.FirstOrDefault(m => m.Module.Id == feature.ModuleId);

                        if (fmi == null)
                        {
                            fmi = new FeatureModuleItem();
                            fmi.Module = Foresight.Fleet.Services.User.FeatureModule.GetModule(feature.ModuleId);
                            fmi.Features.Add(feature);
                            list.Add(fmi);
                        }
                        else
                            fmi.Features.Add(feature);
                    }

                    return list.ToArray();
                }
                else
                    return new FeatureModuleItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetFeaturesDefinedOnUser()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var useriid = Request.Form["ClientData"];
                    var client = CreateClient<Foresight.Fleet.Services.User.PermissionProvider>();
                    KeyValuePair<int, Foresight.Fleet.Services.User.Permissions[]>[] pms = client.GetFeaturesDefinedOnUser(SystemParams.CompanyID, useriid);

                    return pms;
                }
                else
                    return new KeyValuePair<int, Foresight.Fleet.Services.User.Permissions[]>[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        #endregion

        protected override bool AllowCurrentLoginSessionEnter()
        {
            var f = base.AllowCurrentLoginSessionEnter();
            if (!f)
            {
                return false;
            }

            // check whether you are admin.
            var session = GetCurrentLoginSession();
            if (session == null || session.User == null)
            {
                return false;
            }
            var ui = UserManagement.GetUserByIID(session.User.UID);
            return ui != null && ui.UserType >= UserTypes.Admin;
        }

        protected override bool ThrowIfNotAllowed { get { return true; } }

        private object GetUsers()
        {
            var items = UserManagement.GetUsers().OrderBy(u => u.ID).ToArray();
            return items;
        }

        private object GetUserInfo()
        {
            var uid = Request.Form["ClientData"];
            var user = UserManagement.GetUserByIID(uid);
            if (user == null)
                user = new UserInfo();
            return user;
        }

        private object SaveUser(bool adduser)
        {
            var session = GetCurrentLoginSession();
            if (session == null) return "";

            var content = Request.Form["ClientData"];
            content = HttpUtility.HtmlDecode(content);
            var user = JsonConvert.DeserializeObject<UserObject>(content);
            var item = user.UserInfo;

            try
            {
                if (adduser)
                {
                    if (string.IsNullOrWhiteSpace(item.ID))
                    {
                        throw new ArgumentException("User ID cannot be empty.");
                    }
                    if (string.IsNullOrWhiteSpace(item.DisplayName))
                    {
                        throw new ArgumentException("User name cannot be empty.");
                    }
                    item.Active = true;
                    item.IID = UserManagement.AddUser(item, item.TransPass, session.User.UID, session.SessionID, Request.UserHostName);
                }
                else
                {
                    UserManagement.UpdateUserInfo(item, session.User.UID, session.SessionID, Request.UserHostName);
                    UserManagement.SaveUserGroups(item.IID, item.GroupIDs);
                    // save subscribe message
                    if (user.Subscribe != null)
                    {
                        user.Subscribe.UserIID = item.IID;
                        FI.FIC.Models.WorkspaceManager.SaveSubscribeMessageByEmail(user.Subscribe, item.IID);
                    }

                    if (user.Features != null && user.Features.Length > 0)
                    {
                        var client = CreateClient<Foresight.Fleet.Services.User.PermissionProvider>();
                        client.UpdateFeaturesForUser(SystemParams.CompanyID, item.IID, user.Features, session.User.UID);
                    }
                    if (SystemParams.HasLicense("EmailSubscribe") && user.Schedule != null)
                    {
                        FI.FIC.Models.Schedule.ScheduleManager.SaveEmailScheduleItems(item.IID, user.Schedule, "en-us");
                    }
                }

            }
            catch (Exception ex)
            {
                return ex.Message;
            }

            return new string[] { item.IID, "Saved successfully." };
        }

        private string DeleteUser()
        {
            var session = GetCurrentLoginSession();
            if (session == null) return "";

            var iid = Request.Form["ClientData"];
            Guid guid;
            if (!Guid.TryParse(iid, out guid))
            {
                throw new ArgumentException("User IID is not valid.");
            }
            else if (!UserManagement.CanDeleteUser(iid))
            {
                throw new Exception("This user cannot be deleted.");
            }
            CreateClient<Foresight.Fleet.Services.User.UserQueryClient>().DeleteUser(iid, session.User.UID, "");
            return "OK";
        }

        private object ResetPassword()
        {
            var session = GetCurrentLoginSession();
            if (session == null) return "";
            var clientdata = Request.Form["ClientData"].Split((char)170);
            var iid = HttpUtility.HtmlDecode(clientdata[0]);
            var password = HttpUtility.HtmlDecode(clientdata[1]);

            Guid guid;
            if (!Guid.TryParse(iid, out guid))
            {
                throw new ArgumentException("User IID is not valid.");
            }

            UserManagement.ResetPassword(iid, password, session.User.UID, session.SessionID, Request.UserHostName);
            return "OK";
        }

        private object GetUserMachineGroup()
        {
            if (GetCurrentLoginSession() != null)
            {
                var clientdata = Request.Form["ClientData"];
                var useriid = HttpUtility.HtmlDecode(clientdata);

                var allMachines = MachineManagement.GetMachineGroups("");
                var machines = MachineManagement.GetMachineGroupByUser(useriid);
                UserMachineGroupInfoItem mgi = new UserMachineGroupInfoItem();
                mgi.AllMachineGroups = allMachines.OrderBy((m) => m.GroupName).ToArray();
                mgi.MachineGroups = machines.OrderBy((m) => m.GroupName).ToArray();

                return mgi;
            }
            else
                return "OK";
        }
        private object SaveUserMachineGroup()
        {
            if (GetCurrentLoginSession() != null)
            {
                string clientdata = Request.Form["ClientData"];
                clientdata = HttpUtility.HtmlDecode(clientdata);
                UserMachineGroupSaveItem umg = JsonConvert.DeserializeObject<UserMachineGroupSaveItem>(clientdata);

                MachineManagement.SaveUserMachineGroup(umg.UserIID, umg.GroupIDs);

                return "OK";
            }
            return "Failed";
        }

        private object GetAllGroups()
        {
            if (GetCurrentLoginSession() != null)
            {
                var groups = UserManagement.GetGroups();
                return groups;
            }
            return "Failed";
        }

        private object GetGroupsByUser()
        {
            if (GetCurrentLoginSession() != null)
            {
                string clientdata = Request.Form["ClientData"];
                clientdata = HttpUtility.HtmlDecode(clientdata);

                var groups = UserManagement.GetGroupsByUser(clientdata);
                return groups;
            }
            return "Failed";
        }

        private MaintenanceMachineInfo[] GetSelectedMachines()
        {
            var contactid = Request.Form["ClientData"];
            var machines = MachineManagement.GetContactMachinesByID(contactid);

            return machines.OrderBy(m => m.VIN).ToArray();
        }

        private object[] GetSelectedAssets()
        {
            var clientdata = Request.Form["ClientData"].Split((char)170);
            var companyId = HttpUtility.HtmlDecode(clientdata[0]);
            if (string.IsNullOrEmpty(companyId))
            {
                companyId = SystemParams.CompanyID;
            }
            var uid = HttpUtility.HtmlDecode(clientdata[1]);

            var machines = CreateClient<AssetDataAdjustClient>(companyId).GetAssetsAssignedToUser(companyId, uid);

            return machines.OrderBy(m => m.VIN).Select(m => new
            {
                ID = m.Id,
                Name = string.IsNullOrEmpty(m.Name2) ? m.Name : m.Name2,
                m.VIN,
                m.MakeName,
                m.ModelName,
                m.TypeName
            }).ToArray();
        }

        private string AssignAssetsToUser()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var companyId = HttpUtility.HtmlDecode(clientdata[0]);
                    if (string.IsNullOrEmpty(companyId))
                    {
                        companyId = SystemParams.CompanyID;
                    }
                    var uid = HttpUtility.HtmlDecode(clientdata[1]);
                    var machineids = HttpUtility.HtmlDecode(clientdata[2]);

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

                    CreateClient<AssetDataAdjustClient>(companyId).AssignAssetsToUser(companyId, uid, ids);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string RemoveAssignedAssetsFromUser()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var companyId = HttpUtility.HtmlDecode(clientdata[0]);
                    if (string.IsNullOrEmpty(companyId))
                    {
                        companyId = SystemParams.CompanyID;
                    }
                    var uid = HttpUtility.HtmlDecode(clientdata[1]);
                    var machineids = HttpUtility.HtmlDecode(clientdata[2]);

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

                    CreateClient<AssetDataAdjustClient>(companyId).RemoveAssignedAssetsFromUser(companyId, uid, ids);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string SaveContactMachines()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var contactid = HttpUtility.HtmlDecode(clientdata[0]);
                    var machineids = HttpUtility.HtmlDecode(clientdata[1]);

                    string[] ids = JsonConvert.DeserializeObject<string[]>(machineids);

                    UserManagement.SaveUserMachines(contactid, ids);

                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetJobsiteList()
        {
            try
            {
                JobSiteViewItem[] items = null;
                if (GetCurrentLoginSession() != null)
                {
                    var s = Request.Form["ClientData"];
                    s = HttpUtility.UrlDecode(s);

                    var jss = CreateClient<JobSiteProvider>().GetJobSiteItems(SystemParams.CompanyID, "", false);
                    List<JobSiteViewItem> list = new List<JobSiteViewItem>();
                    foreach (var js in jss)
                    {
                        JobSiteViewItem item = new JobSiteViewItem();
                        item.ID = js.ID;
                        item.Name = js.Name;

                        list.Add(item);
                    }
                    items = list.ToArray();
                }
                else
                {
                    items = new JobSiteViewItem[0];
                }
                return items;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetSelectedJobsites()
        {
            try
            {
                JobSiteViewItem[] items = null;
                if (GetCurrentLoginSession() != null)
                {
                    var contactid = Request.Form["ClientData"];
                    contactid = HttpUtility.UrlDecode(contactid);

                    items = JobSitesManagement.GetUserJobsites(contactid);

                }
                else
                {
                    items = new JobSiteViewItem[0];
                }
                return items;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string SaveContactJobsites()
        {
            try
            {
                if (GetCurrentLoginSession() != null)
                {
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var contactid = HttpUtility.HtmlDecode(clientdata[0]);
                    var jobsiteids = HttpUtility.HtmlDecode(clientdata[1]);

                    string[] ids = JsonConvert.DeserializeObject<string[]>(jobsiteids);

                    UserManagement.SaveUserJobsites(contactid, ids);

                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private MaintenanceMachineInfo[] GetMachineList()
        {
            var session = GetCurrentLoginSession();
            var s = Request.Form["ClientData"];
            var p = JsonConvert.DeserializeObject<StringKeyValue>(s);

            var machines = MaintenanceManagement.GetMaintenanceMachines(session.SessionID, int.Parse(p.Key), p.Value, session.User.UID)
                .OrderBy(m => m.ShowName)
                .ToArray();

            return machines;
        }

        private class UserMachineGroupInfoItem
        {
            public MachineGroup[] AllMachineGroups { get; set; }
            public MachineGroup[] MachineGroups { get; set; }
        }
        private class UserMachineGroupSaveItem
        {
            public string UserIID { get; set; }
            public string[] GroupIDs { get; set; }
        }

        public class FeatureModuleItem
        {
            public Foresight.Fleet.Services.User.FeatureModule Module { get; set; }
            public List<Foresight.Fleet.Services.User.Feature> Features { get; set; } = new List<Foresight.Fleet.Services.User.Feature>();
        }
    }
}
