using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using C4IT.Logging;
using C4IT.MsGraph;
using C4IT.LIAM;
using System.Reflection;
using static C4IT.Logging.cLogManager;

namespace LiamTestTeams
{
    public class TreeNodeMsTeamsRoot : TreeNodeRoot
    {
        public cMsGraphSharepoint MsSharepoint;

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

        public override string ToString()
        {
            var s = MsSharepoint?.Base?.Me?.DisplayName;
            return s ?? "";
        }

        public override string GetInfoText()
        {
            var s = MsSharepoint?.Base?.Me?.PublisherDomain;
            return s ?? "";
        }

        public override async Task<bool> LogonAsync()
        {   
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var MsGraph = new cMsGraphBase();

                var LogonInfo = new cMsGraphLogonInfo()
                {
                    Tenant = Provider.Domain,
                    ClientID = Provider.Credential.Identification,
                    ClientSecret = Provider.Credential.Secret
                };

                var isOk = await MsGraph.LogonAsync(LogonInfo);
                if (!isOk)
                    return false;

                MsSharepoint = new cMsGraphSharepoint(MsGraph);

                return true;
            }
            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);
            var RetVal = new List<TreeNodeBase>();
            try
            {
                var lstTeams = await MsSharepoint.RequestTeamsListAsync();
                if (lstTeams == null || lstTeams.Count == 0)
                    return RetVal;

                foreach (var Entry in lstTeams.Values)
                {
                    var Team = await MsSharepoint.RequestGroupInfoAsync(Entry);
                    if (Team == null)
                        continue;

                    var Node = new TreeNodeMsTeamsGroup(this, Team);
                    RetVal.Add(Node);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return RetVal;
        }

        public override string getLastError()
        {
            return MsSharepoint?.Base?.LastErrorMessage ?? "";
        }

    }

    public class TreeNodeMsTeamsGroup : TreeNodeBase
    {
        public string ID;
        public cMsGraphResultGroup Group = null;
        public TreeNodeMsTeamsRoot Root;

        public TreeNodeMsTeamsGroup(TreeNodeMsTeamsRoot Root, cMsGraphResultGroup MsGroup)
        {
            this.Root = Root;
            this.ID = MsGroup.ID;
            Group = MsGroup;
        }

        public override string ToString()
        {
            if (Group == null)
                return "";
            return Group.DisplayName;
        }

        public override bool IsResolved()
        {
            if (Group == null)
                return false;
            if (Group.Channels == null)
                return false;
            return true;
        }

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

            var strInfo = "Type: Group";
            strInfo += $"\r\n\r\nDisplay name: {Group.DisplayName}";
            strInfo += $"\r\nDescription: {Group.Description}";
            strInfo += $"\r\nVisibility: {Group.Visibility}";
            strInfo += $"\r\n\r\nID: {Group.ID}";
            strInfo += $"\r\nSID: {Group.SID}";
            strInfo += $"\r\nMail enabled: {Group.MailEnabled}";
            strInfo += $"\r\nMail address: {Group.MailAddress}";

            if (Group.Drive != null)
            {
                strInfo += $"\r\n\r\nDrive name: {Group.Drive.DisplayName}";
                strInfo += $"\r\nDrive type: {Group.Drive.DriveType}";
                strInfo += $"\r\nDrive ID: {Group.Drive.ID}";

                if (Group.Drive.Root != null)
                {
                    strInfo += $"\r\n\r\nRoot name: {Group.Drive.Root.DisplayName}";
                    strInfo += $"\r\nRoot ID: {Group.Drive.Root.ID}";
                }
            }

            return strInfo;
        }

        override public async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {
            if (Group == null || ResolveAlways)
                Group = await Root.MsSharepoint.RequestGroupInfoAsync(ID);
            if (Group == null)
                return null;

            if (Group.Drive == null)
                if (!await Group.ResolveDrive(Root.MsSharepoint))
                    return null;

            if (Group.Drive.Root == null)
                if (!await Group.Drive.ResolveRoot(Root.MsSharepoint))
                    return null;

            if (Group.Channels == null)
                if (!await Group.ResolveChannels(Root.MsSharepoint))
                    return null;

            if (Group.Drive.Root.Folders == null)
                await Group.Drive.Root.ResolveFolders(Root.MsSharepoint);

            var RetVal = new List<TreeNodeBase>(Group.Channels.Count);
            foreach (var Entry in Group.Channels.Values)
            {
                var Item = new TreeNodeMsTeamsChannel(this, Entry);
                RetVal.Add(Item);
            }

            return RetVal;
        }

        public override int ImageIndex()
        {
            return 0;
        }

        public override dynamic GetJsonObject()
        {
            return Group.Result; ;
        }

        public override string getLastError()
        {
            return Root?.MsSharepoint?.Base?.LastErrorMessage ?? "";
        }

    }

    public class TreeNodeMsTeamsFolder : TreeNodeBase
    {
        public cMsGraphResultFileObject Folder = null;
        public TreeNodeMsTeamsRoot Root;

        public TreeNodeMsTeamsFolder(TreeNodeMsTeamsRoot Root, TreeNodeBase Parent, cMsGraphResultFileObject Folder)
        {
            this.Root = Root;
            this.Parent = Parent;
            this.Folder = Folder;
        }

        public override string ToString()
        {
            if (Folder == null)
                return "";
            return Folder.DisplayName;
        }

        public override bool IsResolved()
        {
            if (Folder != null && Folder.Folders != null)
                return true;
            return false;
        }

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

            var strInfo = $"Type: Folder";
            strInfo += $"\r\n\r\nDisplay name: {Folder.DisplayName}";
            strInfo += $"\r\nIs folder: {Folder.IsFolder}";
            strInfo += $"\r\n\r\nID: {Folder.ID}";

            return strInfo;
        }

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

                if (string.IsNullOrEmpty(Folder.Context) || ResolveAlways)
                {
                    var Folder2 = await Root.MsSharepoint.RequestFileObjectInfo(Folder.DriveID, Folder.ID, Folder.Drive);
                    if (Folder2 != null)
                        Folder = Folder2;
                }

                if (Folder.Folders == null)
                    if (!await Folder.ResolveFolders(Root.MsSharepoint))
                        return null;

                var RetVal = new List<TreeNodeBase>()
                {
                    new TreeNodeMsTeamsPermissionList(Root, this, this.Folder)
                };

                foreach (var Entry in Folder.Folders.Values)
                {
                    var Item = new TreeNodeMsTeamsFolder(Root, this, Entry);
                    RetVal.Add(Item);
                }

                return RetVal;
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }
            return null;
        }

        public override int ImageIndex()
        {
            return 3;
        }

        public override dynamic GetJsonObject()
        {
            return Folder.Result; ;
        }

        public override string getLastError()
        {
            return Root?.MsSharepoint?.Base?.LastErrorMessage ?? "";
        }

    }

    public class TreeNodeMsTeamsChannel : TreeNodeBase
    {
        public cMsGraphResultChannel Channel = null;
        public TreeNodeMsTeamsRoot Root;

        public TreeNodeMsTeamsChannel(TreeNodeMsTeamsGroup Group, cMsGraphResultChannel Channel) : base()
        {
            this.Root = Group.Root;
            this.Parent = Group;
            this.Channel = Channel;
        }

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

            var strInfo = $"Type: Channel";
            strInfo += $"\r\n\r\nDisplay name: {Channel.DisplayName}";
            var hasRootFolder = Channel.RootFolder != null;
            strInfo += $"\r\nHas root folder: {hasRootFolder}";
            strInfo += $"\r\n\r\nID: {Channel.ID}";

            return strInfo;
        }

        public override string ToString()
        {
            if (Channel == null)
                return "";
            return Channel.DisplayName;
        }

        public override bool IsResolved()
        {
            if (Channel != null && Channel.RootFolderResolved)
                return true;
            return false;
        }

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

            if (Channel.RootFolder == null || ResolveAlways)
                if (!await Channel.ResolveRootFolder(Root.MsSharepoint))
                    return new List<TreeNodeBase>();

            if (Channel.RootFolder.Folders == null || ResolveAlways)
                if (!await Channel.RootFolder.ResolveFolders(Root.MsSharepoint))
                    return new List<TreeNodeBase>();

            var RetVal = new List<TreeNodeBase>(Channel.RootFolder.Folders.Count)
            {
                new TreeNodeMsTeamsPermissionList(Root, this, Channel.RootFolder)
            };
            foreach (var Entry in Channel.RootFolder.Folders.Values)
            {
                var Item = new TreeNodeMsTeamsFolder(Root, this, Entry);
                RetVal.Add(Item);
            }

            return RetVal;
        }

        public override int ImageIndex()
        {
            if (Channel != null)
                if (Channel.RootFolder != null)
                    return 2;
            return 1;
        }

        public override dynamic GetJsonObject()
        {
            return Channel.Result; ;
        }

        public override string getLastError()
        {
            return Root?.MsSharepoint?.Base?.LastErrorMessage ?? "";
        }


    }

    public class TreeNodeMsTeamsPermissionList : TreeNodeBase
    {
        public cMsGraphResultFileObject Folder = null;
        public TreeNodeMsTeamsRoot Root;

        public TreeNodeMsTeamsPermissionList(TreeNodeMsTeamsRoot Root, TreeNodeBase Parent, cMsGraphResultFileObject Folder) : base()
        {
            this.Root = Root;
            this.Parent = Parent;
            this.Folder = Folder;
        }

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

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

        public override bool IsResolved()
        {
            if (Folder != null && Folder.Permissions != null)
                return true;
            return false;
        }

        override public async Task<List<TreeNodeBase>> ResolveAsync(bool ResolveAlways = false)
        {
            var RetVal = new List<TreeNodeBase>();
            if (Folder.Permissions == null || ResolveAlways)
                await Folder.ResolvePermissions(Root.MsSharepoint);

            if (Folder.Permissions != null)
                foreach (var Entry in Folder.Permissions)
                {
                    if (Entry.Identities == null || Entry.Identities.Count == 0)
                    {
                        var Item = new TreeNodeMsTeamsPermission(this, Entry, null);
                        RetVal.Add(Item);
                    }
                    else
                    {
                        foreach (var Identity in Entry.Identities)
                        {
                            var Item = new TreeNodeMsTeamsPermission(this, Entry, Identity);
                            RetVal.Add(Item);
                        }

                    }


                }

            return RetVal;
        }

        public override int ImageIndex()
        {
            return 4;
        }

        public override dynamic GetJsonObject()
        {
            return "";
        }

        public override bool SupportPermissionAdd()
        {
            if (Parent is TreeNodeMsTeamsFolder Fo)
                if (Fo.Folder != null)
                    return true;
            return false;
        }

        public override bool SupportPermissionRemoveByValue()
        {
            return true;
        }

        public override async Task<bool> AddPermission(eLiamAccessRoles Role, string Identity)
        {
            try
            {
                var MsGraphRole = cLiamProviderMsTeams.getMsGraphRole(Role);

                if (this.Parent is TreeNodeMsTeamsFolder Fo)
                    if (Fo.Folder != null)
                    {
                        var Roles = new List<cMsGraphResultPermission.ePermissionRole>()
                        {
                            MsGraphRole
                        };
                        var RetVal = await Fo.Folder.AddPermission(Root.MsSharepoint, Roles, cMsGraphResultPermission.eDriveReceipientType.email, Identity);
                        if (RetVal != null)
                            return true;
                    }
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

        public override async Task<bool> RemovePermissionByValue(eLiamAccessRoles Role, string Identity)
        {
            try
            {
                var MsGraphRole = cLiamProviderMsTeams.getMsGraphRole(Role);

                if (this.Parent is TreeNodeMsTeamsFolder Fo)
                    if (Fo.Folder != null)
                    {
                        var RetVal = await Fo.Folder.RemovePermission(Root.MsSharepoint, MsGraphRole, Identity);
                        return RetVal;
                    }
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

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

        public override string getLastError()
        {
            return Root?.MsSharepoint?.Base?.LastErrorMessage ?? "";
        }

    }

    public class TreeNodeMsTeamsPermission : TreeNodeBase
    {
        public cMsGraphResultPermission Permission = null;

        public cMsGraphResultPermission.cMsGraphPermissionIdentity Identity = null;
        public TreeNodeMsTeamsRoot Root;

        public TreeNodeMsTeamsPermission(TreeNodeMsTeamsPermissionList Folder, cMsGraphResultPermission Permission, cMsGraphResultPermission.cMsGraphPermissionIdentity Identity) : base()
        {
            this.Root = Folder.Root;
            this.Parent = Folder;
            this.Permission = Permission;
            this.Identity = Identity;
        }

        public override bool AutoResolved()
        {
            return true;
        }

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

            var strInfo = $"Type: Permission (-unknown-)";

            if (Permission is cMsGraphResultPermission.PermissionDirect)
                strInfo = $"Type: Permission (direkt)";
            else if (Permission is cMsGraphResultPermission.PermissionLink Link)
            {
                strInfo = $"Type: Permission (link)";
                strInfo += $"\r\n\r\nScope: {Link?.Scope ?? ""}";
                strInfo += $"\r\nPrevents download: {Link?.PreventsDownload ?? ""}";
                strInfo += $"\r\nWEB URL: {Link?.WebUrl ?? ""}";
            }

            strInfo += $"\r\n\r\nPermission ID: {Permission?.ID ?? ""}";
            strInfo += $"\r\nIs inherited: {Permission?.isInherited.ToString() ?? ""}";

            var strRoles = "";
            if (Permission.Roles != null)
                foreach (var Entry in Permission.Roles)
                {
                    if (strRoles != "")
                        strRoles += "";
                    strRoles += Entry;
                }

            strInfo += $"\r\n\r\nRoles: {strRoles}";

            if (Identity == null)
            {
                strInfo += $"\r\n\r\nNo identities assigned";
            }
            else
            {
                var strType = "-unknown-";
                switch (Identity?.IdentityType)
                {
                    case cMsGraphResultPermission.cMsGraphPermissionIdentity.eIdentityType.application:
                        strType = "Application";
                        break;
                    case cMsGraphResultPermission.cMsGraphPermissionIdentity.eIdentityType.device:
                        strType = "Device";
                        break;
                    case cMsGraphResultPermission.cMsGraphPermissionIdentity.eIdentityType.user:
                        strType = "User or group";
                        break;
                }
                strInfo += $"\r\n\r\nIdentity type: {strType}";
                strInfo += $"\r\nIdentity name: {Identity?.DisplayName ?? ""}";
                strInfo += $"\r\nIdentity email: {Identity?.EMail ?? ""}";
                strInfo += $"\r\nIdentity ID: {Identity?.ID ?? ""}";
            }


            return strInfo;
        }

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

                var strName = "Unknown:";
                if (Permission is cMsGraphResultPermission.PermissionDirect)
                    strName = "Direct: ";
                else if (Permission is cMsGraphResultPermission.PermissionLink)
                    strName = "Link: ";

                strName += $" {Identity?.DisplayName ?? "(no identities)"} =";

                var strRoles = "";
                if (Permission.Roles != null)
                    foreach (var Entry in Permission.Roles)
                        strRoles += " " + Entry;
                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()
        {
            if (Permission.isInherited)
                return 5;


            return 6;
        }

        public override dynamic GetJsonObject()
        {
            return Permission.Result;
        }

        public override bool SupportPermissionRemoveDirect()
        {
            return true;
        }

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

                if (Identity == null)
                {
                    var rv = await Permission.Delete(Root.MsSharepoint);
                    return rv;
                }

                var RT = cMsGraphResultPermission.eDriveReceipientType.email;
                var RN = Identity?.EMail;
                if (!string.IsNullOrEmpty(Identity.ID))
                {
                    RT = cMsGraphResultPermission.eDriveReceipientType.objectId;
                    RN = Identity.ID;
                }
                var RetVal = await Permission.RevokeGrant(Root.MsSharepoint, RT, RN);

                return RetVal;
            }
            catch (Exception E)
            {
                cLogManager.LogException(E);
            }

            return false;
        }

        public override string getLastError()
        {
            return Root?.MsSharepoint?.Base?.LastErrorMessage ?? "";
        }

    }

}
