using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

using C4IT.LIAM;
using C4IT.Logging;
using static C4IT.Logging.cLogManager;

namespace LiamTestTeams
{
    public class TreeNodeLiamRoot : TreeNodeRoot
    {
        public cLiamProviderBase ProviderBase;

        public TreeNodeLiamRoot(cLiamProviderData Provider) : base(Provider)
        {
        }

        public bool Load()
        {   
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var LiamCfg = new cLiamConfiguration();
                ProviderBase = cLiamProviderBase.CreateInstance(LiamCfg, Provider);

                return ProviderBase != null;
            }
            catch (Exception E)
            {
                LogException(E);
                return false;
            }
            finally
            {
                LogMethodEnd(CM);
            }


        }

        public override async Task<bool> LogonAsync()
        {   
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (ProviderBase == null)
                    if (!Load())
                        return false;

                var RetVal =  await ProviderBase.LogonAsync();

                return RetVal;
            }
            catch (Exception E)
            {
                LogException(E);
                return false;
            }
            finally
            {
                LogMethodEnd(CM);
            }


        }

        public override async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {   
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var lstLiamNodes = await ProviderBase.getDataAreasAsync(0);
                if (lstLiamNodes == null)
                    return null;

                var RetVal = new List<TreeNodeBase>();
                foreach (var Entry in lstLiamNodes)
                {
                    var Node = new TreeNodeLiamNode(Entry);
                    RetVal.Add(Node);
                }

                return RetVal;
            }
            catch (Exception E)
            {
                LogException(E);
                return null;
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }
    }

    public class TreeNodeLiamNode : TreeNodeBase
    {
        public cLiamDataAreaBase DataArea;

        private bool privIsResolved = false;

        private List<cLiamUserInfo> Owners = null;

        public TreeNodeLiamNode(cLiamDataAreaBase DataArea)
        {
            this.DataArea = DataArea;
        }

        public override string ToString()
        {
            return DataArea?.TechnicalName ?? "";
        }

        public override int ImageIndex()
        {
            if (DataArea == null)
                return iconIndexUnknown;

            switch (DataArea.DataType)
            {
                case eLiamDataAreaTypes.MsTeamsTeam:
                    return 0;
                case eLiamDataAreaTypes.MsTeamsChannel:
                    return 1;
                case eLiamDataAreaTypes.MsTeamsFolder:
                    return 3;
                default:
                    return iconIndexUnknown;

            }
        }

        public override bool IsResolved()
        {
            return privIsResolved;
        }

        public override async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {
            if (DataArea == null)
                return null;

            Owners = await DataArea.GetOwnersAsync();

            var Children = await DataArea.getChildrenAsync(0);
            if (Children == null)
                return null;

            var RetVal = new List<TreeNodeBase>();
            if (DataArea.SupportsPermissions)
                RetVal.Add(new TreeNodeLiamPermissionList(DataArea));
            foreach (var Entry in Children)
            {
                var Node = new TreeNodeLiamNode(Entry);
                RetVal.Add(Node);
            }

            privIsResolved = true;

            return RetVal;
        }

        public override string GetInfoText()
        {
            var RetVal = $"Technical name: {DataArea?.TechnicalName}";
            RetVal += $"\r\n\r\nData type: {DataArea?.DataType}";
            RetVal += $"\r\nUID: {DataArea?.UID}";
            RetVal += $"\r\nParent UID: {DataArea?.ParentUID}";
            RetVal += $"\r\n\r\nLevel: {DataArea?.Level}";
            RetVal += $"\r\nSupport permissions: {DataArea?.SupportsPermissions}";

            if (Owners != null)
            {
                if (Owners.Count == 0)
                {
                    RetVal += $"\r\n\r\nOwner list is empty (no members)";
                }
                else
                {
                    RetVal += $"\r\n\r\nOwners:";
                    foreach (var Owner in Owners)
                    {
                        RetVal += $"\r\n {Owner.DisplayName}: UPN='{Owner.UserPrincipalName}', SID='{Owner.SID}'";
                    }
                }
            }

            return RetVal;
        }

        public override string GetUID()
        {
            return DataArea.UID;
        }

        public override async Task<TreeNodeBase> LoadFromUID()
        {   
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var UID = GetUID();
                if (string.IsNullOrEmpty(UID))
                    return null;

                var R = await DataArea.Provider.LoadDataArea(UID);
                if (R == null)
                    return null;

                var RetVal = new TreeNodeLiamNode(R);

                return RetVal;
            }
            catch (Exception E)
            {
                LogException(E);
                return null;
            }
            finally
            {
                LogMethodEnd(CM);
            }

        }

    }

    public class TreeNodeLiamPermissionList : TreeNodeBase
    {
        public cLiamDataAreaBase DataArea;

        private bool privIsResolved = false;

        public TreeNodeLiamPermissionList(cLiamDataAreaBase DataArea)
        {
            this.DataArea = DataArea;
        }

        public override string GetInfoText()
        {
            return "";
        }

        public override string ToString()
        {
            return "Permissions";
        }

        public override bool IsResolved()
        {
            return privIsResolved;
        }

        override public async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {
            try
            {
                var RetVal = new List<TreeNodeBase>();
                var Perms = await DataArea.GetPermissionsAsync(ResolveAlways);
                if (Perms == null)
                    return null;

                foreach (var Entry in Perms)
                {
                    RetVal.Add(new TreeNodeLiamPermission(Entry, DataArea));
                }

                privIsResolved = true;
                return RetVal;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
            }
                
            return null;
        }

        public override int ImageIndex()
        {
            return 4;
        }

        public override dynamic GetJsonObject()
        {
            return null;
        }

        public override bool SupportPermissionAdd()
        {
            return true;
        }

        public override bool SupportPermissionRemoveByValue()
        {
            return false;
        }

        public override async Task<bool> AddPermission(eLiamAccessRoles Role, string Identity)
        {
            try
            {
                var UserInfo = new cLiamUserInfo()
                {
                    UserPrincipalName = Identity,
                    EMail = Identity
                };
                var PermResult = await DataArea.GrantPermissionAsync(UserInfo, Role);
                if (PermResult.Valid)
                    return true;
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

        public override async Task<bool> RemovePermissionByValue(eLiamAccessRoles Role, string Identity)
        {
            try
            {
                await Task.Delay(0);
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

        public override List<eLiamAccessRoles> ValidPermissionRoles()
        {
            var RetVal = new List<eLiamAccessRoles>() {
                eLiamAccessRoles.Read,
                eLiamAccessRoles.Write,
                eLiamAccessRoles.Owner
            };
            return RetVal;
        }

        public override string getLastError()
        {
            return "";
        }


    }

    public class TreeNodeLiamPermission : TreeNodeBase
    {
        public cLiamPermissionInfo Permission = null;
        public cLiamDataAreaBase DataArea = null;

        public TreeNodeLiamPermission(cLiamPermissionInfo Permission, cLiamDataAreaBase DataArea) : base()
        {
            this.Permission = Permission;
            this.DataArea = DataArea;
        }

        public override bool AutoResolved()
        {
            return true;
        }

        public override string GetInfoText()
        {
            if (Permission == null)
                return "";

            var strInfo = $"Type: Role memership";


            var strUser = "-unknown-";
            if (Permission.User != null)
            {
                if (Permission.User != null)
                {
                    strUser = Permission.User.DisplayName;
                    if (string.IsNullOrEmpty(strUser))
                        strUser = Permission.User.UserPrincipalName;
                    if (string.IsNullOrEmpty(strUser))
                        strUser = Permission.User.EMail;
                }
            }
            strInfo += $"\r\n\r\nUser or group: {strUser}";


            strInfo += $"\r\n\r\nRole: {Permission.AccessRole}";

            return strInfo;
        }

        public override string ToString()
        {
            try
            {
                if (Permission == null)
                    return "";

                var strName = "Unknown";
                if (Permission.User != null)
                {
                    strName = Permission.User.DisplayName;
                    if (string.IsNullOrEmpty(strName))
                        strName = Permission.User.UserPrincipalName;
                    if (string.IsNullOrEmpty(strName))
                        strName = Permission.User.EMail;
                }
                strName += ": [" ;

                var strRoles = Permission.AccessRole.ToString();

                return strName + strRoles + "]";
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }
            return "";
        }

        public override bool IsResolved()
        {
            return true;
        }

        override public async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {
            await Task.Delay(0);
            return new List<TreeNodeBase>();
        }

        public override int ImageIndex()
        {
            return 6;
        }

        public override dynamic GetJsonObject()
        {
            return null;
        }

        public override bool SupportPermissionRemoveDirect()
        {
            return true;
        }

        public override async Task<bool> RemovePermissionDirect()
        {
            try
            {
                if (Permission == null)
                    return false;
                if (Permission.User == null)
                    return false;


                var RetVal = await DataArea.RevokePermissionAsync(Permission.User, Permission.AccessRole);
                return RetVal;
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

    }
}
