using System;
using System.Collections.Generic;

namespace VCommon.VApplication.Authorization
{
    public class PermissionTree
    {
        private readonly List<PermissionNode> _roots = new();

        private HashSet<string> _codeHashSet = new();

        internal List<PermissionNode> _allNode = new();

        internal HashSet<string> CodeHashSet
        {
            get
            {
                if (null == _codeHashSet) throw new InvalidOperationException("Final called");
                return _codeHashSet;
            }
        }

        public IReadOnlyCollection<PermissionNode> AllNodes { get; private set; }

        public IReadOnlyCollection<PermissionNode> Roots => _roots;

        public PermissionNode CreateRootNode(string code, string name, string description = null, string nameForOperator = null, string descriptionForOperator = null, MultiTenancySides side = MultiTenancySides.Both)
        {
            if (CodeHashSet.Contains(code)) throw new ArgumentException($"重复的权限代码:{code},名称:{name}");
            var node = new PermissionNode(this, code, name, description, nameForOperator, descriptionForOperator, side);
            _roots.Add(node);
            _allNode.Add(node);
            CodeHashSet.Add(code);
            return node;
        }

        public IReadOnlyCollection<PermissionNodeOutput> Filter(MultiTenancySides side, IReadOnlyCollection<string> licPerms)
        {
            return FltTree(_roots, side, new HashSet<string>(licPerms));
        }

        private static IReadOnlyCollection<PermissionNodeOutput> FltTree(IReadOnlyCollection<PermissionNode> nodesFrom, MultiTenancySides side, IReadOnlySet<string> licPerms, List<PermissionNodeOutput> output = null)
        {
            output ??= new List<PermissionNodeOutput>();

            foreach (var node in nodesFrom)
            {
                if (!licPerms.Contains(node.Code)) continue;
                if (node.TenancySide != side) continue;

                var copy = side == MultiTenancySides.Tenant
                    ? new PermissionNodeOutput(node.Code, node.Name, node.Description)
                    : new PermissionNodeOutput(node.Code, node.NameForOperator ?? node.Name, node.DescriptionForOperator ?? node.Description);

                output.Add(copy);

                FltTree(node.Children, side, licPerms, copy.Children);
            }

            return output;
        }

        /// <summary> 完成初始化, 释放并返回重名检查集合, 提供扁平集合, 禁止再加挂节点 </summary>
        public HashSet<string> CompleteAdding()
        {
            var toReturn = _codeHashSet;
            AllNodes = _allNode.ToArray();
            _codeHashSet = null;
            return toReturn;
        }
    }
}
