using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using MECF.Framework.Common.Account.Extends;
using MECF.Framework.Common.Account.Permissions;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.UI.Client.CenterViews.Editors;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Core.Accounts;

namespace MECF.Framework.UI.Client.CenterViews.Configs.Roles
{
    public class RoleManagerClient : Singleton<RoleManagerClient>
    {
        #region Variables

        private List<AppMenu> _appMenuPermSource;
        private List<PermissionControlItem> _recipeColumnPermSource = new();
        private List<PermissionControlItem> _recipeStepPermSource = new();
        private List<PermissionControlItem> _contentPermSource = new();
        
        private readonly RecipeFormatBuilder _recipeBuilder = new();

        #endregion

        #region Properties

        public ObservableCollection<string> ChamberType { get; set; }

        public ObservableCollection<ProcessTypeFileItem> ProcessTypeFileList { get; set; }

        #endregion

        #region Methods

        public bool Initialize()
        {
            var menus = AccountClient.Instance.Service.GetAllMenus();
            _appMenuPermSource = menus;
            if (menus == null)
            {
                LOG.Error("GetMenus method failed,in RoleManagerClient");
                return false;
            }

            //每个Role下再挂一个Recipe权限
            //Recipe名称从RecipeFormat文件中获取
            var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType");
            if (chamberType == null)
            {
                ChamberType = new ObservableCollection<string>() { "Default" };
            }
            else
            {
                ChamberType = new ObservableCollection<string>(((string)(chamberType)).Split(','));
            }

            var processType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedProcessType");
            if (processType == null)
            {
                processType = "Process,Routine";
            }

            ProcessTypeFileList = new ObservableCollection<ProcessTypeFileItem>();
            var recipeProcessType = ((string)processType).Split(',');
            _recipeColumnPermSource = _recipeBuilder.GetRecipeColumnPermSource($"{ChamberType[0]}\\{recipeProcessType[0]}", "PM1");
            _recipeStepPermSource = _recipeBuilder.GetRecipeStepPermSource();
            _contentPermSource = _recipeBuilder.GetContentPermSource($"{ChamberType[0]}\\Content", "RecipeFormat");
            
            return true;
        }

        /// <summary>
        /// 返回包含所有角色的列表。
        /// </summary>
        /// <returns></returns>
        public List<RoleItem> GetAllRoles()
        {
            return RoleAccountProvider.Instance.GetRoles().Select(Create).ToList();
        }

        private RoleItem Create(Role role)
        {
            var ri = new RoleItem(role);
            var headerPerm = RolePermissionMapper.FromMenuPermissionEnum(role.PermissionControlItems["Header"]);
            var mp = new PermissionControlItem("Header", headerPerm, "Header");

            ri.AddMenuInfo(mp);

            //Get Menu information
            foreach (var topMenuItem in _appMenuPermSource)
            {
                foreach (var subMenuItem in topMenuItem.MenuItems)
                {
                    var appName = topMenuItem.ResKey + "." + subMenuItem.ResKey;
                    var id = subMenuItem.MenuID;
                    var appPerm = RolePermissionMapper.FromMenuPermissionEnum(role.GetPermission(id));
                    var perm = new PermissionControlItem(appName, appPerm, id, subMenuItem.Description);
                    ri.AddMenuInfo(perm);
                }
            }

            foreach (var recipeInfo in _recipeColumnPermSource)
            {
                var permType = RolePermissionMapper.FromMenuPermissionEnum(role.GetPermission(recipeInfo.Name));
                var perm = new PermissionControlItem(recipeInfo.Name, permType, recipeInfo.Name, recipeInfo.Description);
                ri.AddRecipeInfo(perm);
            }

            foreach (var stepInfo in _recipeStepPermSource)
            {
                var permType = RolePermissionMapper.FromMenuPermissionEnum(role.GetPermission(stepInfo.Name));
                var perm = new PermissionControlItem(stepInfo.Name, permType, stepInfo.Name, stepInfo.Description);
                ri.AddStepInfo(perm);
            }

            foreach (var contentInfo in _contentPermSource)
            {
                var permType = RolePermissionTrueFalseMapper.FromMenuPermissionEnum(role.GetPermission(contentInfo.Name));
                var perm = new PermissionControlItem(contentInfo.Name, permType, contentInfo.Name, contentInfo.Description);

                ri.AddContentInfo(perm);
            }

            return ri;
        }

        public RoleItem Create()
        {
            var newId = RoleAccountProvider.Instance.GetAvailableID();
            if (string.IsNullOrEmpty(newId))
                throw new InvalidOperationException("no available role ID.");
            
            var r = new RoleItem(newId);

            r.DisplayRoleName = r.RoleName = string.Empty;
            r.DisplayAutoLogoutTime = r.AutoLogoutTime = 10;
            r.DisplayIsAutoLogout = r.IsAutoLogout = false;
            r.DisplayDescription = r.Description = string.Empty;

            r.MenuPermCollection.Add(new PermissionControlItem( "Header", RolePermissionMapper.ReadWrite, "Header"));

            foreach (var topMenuItem in _appMenuPermSource)
            {
                foreach (var subMenuItem in topMenuItem.MenuItems)
                {
                    var mp = new PermissionControlItem(topMenuItem.ResKey + "." + subMenuItem.ResKey,
                        RolePermissionMapper.ReadWrite, subMenuItem.MenuID);
                    r.MenuPermCollection.Add(mp);
                }
            }

            foreach (var perm in _recipeColumnPermSource)
            {
                var recipe = new PermissionControlItem(perm.Name, RolePermissionMapper.ReadWrite, perm.Name, perm.Description);
                r.AddRecipeInfo(recipe);
            }

            foreach (var perm in _recipeStepPermSource)
            {
                var step = new PermissionControlItem(perm.Name, RolePermissionMapper.ReadWrite, perm.Name, perm.Description);
                r.AddStepInfo(step);
            }

            foreach (var perm in _contentPermSource)
            {
                var permission = new PermissionControlItem(perm.Name, RolePermissionTrueFalseMapper.Yes, perm.Name, perm.Description);
                r.AddContentInfo(permission);
            }

            return r;
        }

        public RoleItem Clone(RoleItem originRoleItem)
        {
            var newId = RoleAccountProvider.Instance.GetAvailableID();
            var newRole = new RoleItem(newId)
            {
                RoleName = originRoleItem.RoleName,
                AutoLogoutTime = originRoleItem.AutoLogoutTime,
                IsAutoLogout = originRoleItem.IsAutoLogout,
                Description = originRoleItem.Description,
                DisplayRoleName = originRoleItem.DisplayRoleName,
                DisplayAutoLogoutTime = originRoleItem.DisplayAutoLogoutTime,
                DisplayIsAutoLogout = originRoleItem.DisplayIsAutoLogout,
                DisplayDescription = originRoleItem.DisplayDescription
            };

            foreach (var mInfo in originRoleItem.MenuPermCollection)
            {
                newRole.AddMenuInfo((PermissionControlItem)mInfo.Clone());
            }

            foreach (var rInfo in originRoleItem.RecipePermCollection)
            {
                newRole.AddRecipeInfo((PermissionControlItem)rInfo.Clone());
            }

            foreach (var sInfo in originRoleItem.RecipeStepPermCollection)
            {
                newRole.AddStepInfo((PermissionControlItem)sInfo.Clone());
            }

            foreach (var pInfo in originRoleItem.ContentPermCollection)
            {
                newRole.AddContentInfo((PermissionControlItem)pInfo.Clone());
            }

            return newRole;
        }

        public bool CheckAvailable(RoleItem ri)
        {
            var available = AccountClient.Instance.Service.CheckRoleNotDuplicated(ri.RoleId, ri.RoleName);
            if (!available)
                LOG.Info("Check role fail because the ID or name already exists, in RoleManagerClient");

            return available;
        }

        public bool SaveRole(RoleItem ri, out string reason)
        {
            reason = "";
            if (!CheckAvailable(ri))
            {
                reason = "the role name duplicated.";
                return false;
            }

            var role = new Role(
                ri.RoleId,
                ri.RoleName,
                ri.IsAutoLogout,
                ri.AutoLogoutTime,
                PermissionHelper.PermissionToDictionary(ri.MenuPermCollection, ri.RecipePermCollection,
                    ri.ContentPermCollection, ri.RecipeStepPermCollection),
                ri.Role.IsBuildIn,
                ri.Description
            );
            
            if (RoleAccountProvider.Instance.UpdateRole(role))
            {
                // 如果当前登录用户的角色是刚才保存的角色，则需要从RT更新一次。
                if (BaseApp.Instance.UserContext.Role.RoleId == role.RoleId)
                {
                  var newestRole = AccountClient.Instance.Service.GetRoleByID(role.RoleId);
                  if (newestRole == null)
                      LOG.Error(
                          $"Unable to refresh the current role with ID {role.RoleId}, the role of current session does not updated.");
                  else
                      BaseApp.Instance.UserContext.Role = newestRole;
                }

                return true;
            }

            reason = "it failed to save/update role from RT side, see log for details.";

            LOG.Error("UpdateRoles method failed, in RoleManagerClient");
            return false;
        }

        public bool DeleteRole(string strRoleID)
        {
            var r = AccountClient.Instance.Service.GetRoleByID(strRoleID);
            if (r != null)
            {
                if (RoleAccountProvider.Instance.DeleteRole(strRoleID)) 
                    return true;
                
                LOG.Error("DeleteRole method failed, in RoleManagerClient");
                return false;
            }

            LOG.Warning("Can not find the role to delete, in RoleManagerClient");
            return false;
        }
        
        #endregion
        
    }
}
