using BlazorApp.Model;
using BlazorApp.Pages;
using BootstrapBlazor.Components;
using Core;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.JSInterop;
using System.Diagnostics.CodeAnalysis;
using UIEx;

namespace BlazorApp.Shared
{
    public partial class MainLayout : UIEx.IMainLayout,IDisposable
    {
        private List<MenuItem>? Menus { get; set; }
        private bool IsFullSide { get; set; } = true;

        private bool IsOpen { get; set; }

        private string Theme { get; set; } = "";


        protected NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

        public NLog.Logger Logger
        {
            get { return _logger; }
        }

        [Inject]
        public NavigationManager NavigationManager { get; set; } = null!;

        Core.SysUser _currentUser = null!;
        public Core.SysUser CurrentUser
        {
            get
            {
                if (IsDebug)
                {
                    return SiteDescription.CurrentUser;
                }
                return _currentUser;
            }
            private set
            {
                _currentUser = value;
            }
        }

        public DBLib.DB GetCurrentDb()
        {
            var db = dbFac.CreateDbContext();
            return db;
        }

        [Inject]
        [NotNull]
        ToastService? ToastService { get; set; }

        [Inject]
        DialogService? DlgService { get; set; }

        [Inject]
        IWebHostEnvironment hostingEnvironmen { get; set; } = null!;

        public string WWWPath => hostingEnvironmen.WebRootPath;

        public string UploadPath => Path.Combine(hostingEnvironmen.WebRootPath, "uploads");

        [Inject]
        ILookupService LookupService { get; set; } = null!;

        public IEnumerable<SelectedItem>? GetItemsByKey(string? key)
        {
            if (string.IsNullOrWhiteSpace(key)) return null;
            var k = key?.ToLower()?.Trim();
            if (k.StartsWith("dic"))
            {
                return LookupService.GetItemsByKey(k);
            }
            else if (k.StartsWith("table#"))
            {
                return LookupService.GetItemsByKey(key);
            }
            return LookupService.GetItemsByKey("table#" + key);
        }

        public IEnumerable<SelectedItem>? GetItemsWithEmptyByKey(string? key, string emptyText = "请选择")
        {
            return UIEx.ExFuncs.AddEmptyItem(GetItemsByKey(key), emptyText);
        }

        public string? GetTitle(string table, Guid keyId)
        {
            var o = keyId.ToString().ToLower();
            return LookupService.GetItemsByKey(table)?.Where(c => c.Value.ToLower() == o).Select(c => c.Text).FirstOrDefault();
        }

        bool _popSel = false;
        public async Task<TResult> ShowModalDlg<T, TResult>(string title = "", Dictionary<string, object>? param = null, Action<ResultDialogOption>? option = null, Size dlgSize = Size.Large, bool showFooter = true, bool showOk = false, bool showCloseBtn = true, Func<Task>? beforeClose = null) where T : Microsoft.AspNetCore.Components.ComponentBase, IResultDialog
        {
            TResult result = default(TResult);
            if (!_popSel)
            {
                _popSel = true;
                try
                {
                    Dictionary<string, object> dic = new Dictionary<string, object>();
                    var opt = new ResultDialogOption()
                    {
                        IsKeyboard = true,
                        Title = title,
                        Size = dlgSize,
                        ShowFooter = showFooter,
                        ShowYesButton = showOk,
                        ShowCloseButton = showCloseBtn,
                        ComponentParameters = dic,
                    };
                    dic.Add("CloseDlg", opt.CloseDialogAsync);
                    dic.Add(nameof(PopDlgBase<TResult>.ResultValueChanged), EventCallback.Factory.Create<TResult>(this, async v => { result = v; StateHasChanged(); }));
                    if (beforeClose != null)
                    {
                        dic.Add("BeforeClose", beforeClose);
                    }
                    if (param != null)
                    {
                        foreach (var v in param)
                        {
                            if (!dic.ContainsKey(v.Key))
                            {
                                dic.Add(v.Key, v.Value);
                            }
                        }
                    }
                    //if (typeof(T).IsSubclassOf(typeof(DBComponentBase)))
                    //{
                    //    dic.Add(nameof(DBComponentBase.Wrapper), this);
                    //}
                    if (option != null)
                    {
                        option(opt);
                    }
                    if (DlgService != null)
                    {
                        var r = await DlgService.ShowModal<T>(opt);
                    }
                }
                catch (Exception ex)
                {
                }
            }
            _popSel = false;
            return result;
        }

        public async Task ShowEditDlg<T>(string title = "", Dictionary<string, object>? param = null, Action<DialogOption>? option = null, Size dlgSize = Size.Large, bool showSave = true, bool showFooter = true, Func<Task>? whenSuccess = null, string? okTxt = null, bool showTip = true) where T : EditDlgBase
        {
            var opt = new DialogOption()
            {
                IsKeyboard = true,
                Title = title,
                Size = dlgSize,
                ShowMaximizeButton = true,
                ShowFooter = showFooter
            };
            if (showSave)
            {
                opt.FooterTemplate = _editDlgFooterTemplate;
                if (!string.IsNullOrEmpty(okTxt))
                {
                    opt.FooterTemplate = _footer.Invoke(okTxt);
                }
            }
            Dictionary<string, object> dic = new Dictionary<string, object>();
            if (param != null)
            {
                foreach (var v in param)
                {
                    if (!dic.ContainsKey(v.Key))
                    {
                        dic.Add(v.Key, v.Value);
                    }
                }
            }
            var a = new EditDlgBase.SaveActDelegate();
            dic.Add("SaveDelegate", a);
            dic.Add("CloseDlg", opt.CloseDialogAsync);
            dic.Add("WhenSuccess", whenSuccess);
            _editDlgSave = EventCallback.Factory.Create(this, async () =>
            {
                if (a != null && a.SaveAct != null)
                {
                    if (await a.SaveAct())
                    {
                        await opt.CloseDialogAsync();
                        if (showTip)
                            await SuccessMsg("操作成功！");
                        if (whenSuccess != null)
                            await whenSuccess();
                    }
                }
            });
            //if (typeof(T).IsSubclassOf(typeof(DBComponentBase)))
            //{
            //    dic.Add(nameof(DBComponentBase.Wrapper), this);
            //}
            var component = BootstrapDynamicComponent.CreateComponent<T>(dic);
            opt.BodyTemplate = component.Render();
            option?.Invoke(opt);
            if (DlgService != null)
            {
                await DlgService.Show(opt);
            }
        }

        public async Task ShowDlg<T>(string title = "", IDictionary<string, object>? param = null, Action<DialogOption>? option = null, Size pageSize = Size.Large, bool showFooter = true) where T : IComponent
        {
            Dictionary<string, object> dic = new Dictionary<string, object>();
            if (param != null)
            {
                foreach (var v in param)
                {
                    if (!dic.ContainsKey(v.Key))
                    {
                        dic.Add(v.Key, v.Value);
                    }
                }
            }
            var component = BootstrapDynamicComponent.CreateComponent<T>(dic);
            var opt = new DialogOption()
            {
                IsKeyboard = true,
                Title = title,
                Size = pageSize,
                ShowFooter = showFooter,
                BodyTemplate = component.Render(),
            };
            if (option != null)
            {
                option(opt);
            }
            if (DlgService != null)
            {
                await DlgService.Show(opt);
            }
        }

        [Inject]
        IHttpContextAccessor? httpContextAccessor { get; set; }

        [Inject]
        AuthenticationStateProvider authenticationStateProvider { get; set; } = null!;

        public string BreadCrumb { get; set; } = "首页";

        public Guid? CurrentMenuId { get; set; }

        [Inject]
        public IDbContextFactory<DBLib.DB> dbFac { get; private set; } = null!;

        [CascadingParameter]
        public App App { get; set; } = null!;

        [CascadingParameter]
        public Routes Routes { get; set; } = null!;

        protected async override Task OnInitializedAsync()
        {
            if (Routes != null) Routes.SetMainLayout(this);
            if (!IsDebug || CurrentUser == null)
            {
                var authState = await authenticationStateProvider.GetAuthenticationStateAsync();
                var user = authState.User;
                if (user == null || user.Identity?.IsAuthenticated == false)
                {
                    nav.NavigateTo("/login", true);
                }
                else
                {
                    CurrentUser = SysUser.GetWebUserFromClarms(user.Claims.ToList());
                }
            }

            //NavigationManager.LocationChanged += HandleLocationChanged;
            await InitMenus();
            await base.OnInitializedAsync();
        }

        private async Task InitMenus()
        {
            if (Menus == null || Menus.Count <= 0)
            {
                using var db = GetCurrentDb();
                if (CurrentUser?.IsAdmin == true || IsDebug)
                {
                    Menus = SiteDescription.GetAllMenus();
                }
                else
                {
                    Menus = (await GetMenusByUser(db, CurrentUser?.Roles?.ToList())).Select(x => (MenuItem)x).ToList();
                }
            }
        }

        #region GetUserMenu
        List<MenuItem> _currentMenus = new List<MenuItem>();
        async Task<List<MenuItem>> GetMenusByUser(DBLib.DB db, List<Guid>? roleIds)
        {
            if (_currentMenus.Count == 0)
            {
                List<MenuItem> newTree = new List<MenuItem>();
                if (roleIds == null) return newTree;
                var menus = (await db.SRoleRightsRel.Where(x => roleIds.Contains(x.RoleId)).ToListAsync()).GroupBy(x => x.SMenuRightID).ToList();
                var sRoles = CurrentUser.Roles.Select(x => x.ToString("N").ToLower()).ToList();
                var allMenus = SiteDescription.GetAllMenus();
                List<Guid> foundResult = new List<Guid>();
                foreach (var m in menus)
                {
                    GetUsedMenus(m.First().SMenuRightID, foundResult);
                }
                foreach (var m in allMenus)
                {
                    BuildUserRootTree(allMenus, m, foundResult, newTree, menus);
                }
                _currentMenus.AddRange(newTree);
            }
            return _currentMenus;
        }

        /// <summary>
        /// 获得用户所有的菜单ID
        /// </summary>
        /// <param name="allMenus"></param>
        /// <param name="menu"></param>
        /// <param name="foundResult">结果集</param>
        void GetUsedMenus(Guid menu, List<Guid> foundResult)
        {
            if (menu == Guid.Parse("9E0FF257-BCB9-4ECC-A0FF-048FB4BAE586"))
            {
                var ll = 0;
            }
            if (!foundResult.Contains(menu)) foundResult.Add(menu);
            var parent = SiteDescription.GetAllMenusFlat().FirstOrDefault(x => x.Items.Any(x => Guid.Parse(x.Id!) == menu));
            if (parent != null && !foundResult.Contains(parent.Id.ToGuid()))
            {
                GetUsedMenus(Guid.Parse(parent.Id!), foundResult);
            }
        }

        /// <summary>
        /// 获得用户根目录
        /// </summary>
        /// <param name="allMenus"></param>
        /// <param name="m"></param>
        /// <param name="foundResult"></param>
        /// <param name="newTree"></param>
        /// <param name="rights"></param>
        void BuildUserRootTree(List<MenuItem> allMenus, MenuItem m, List<Guid> foundResult, List<MenuItem> newTree, IList<IGrouping<Guid, DBLib.SRoleRightsRel>> rights)
        {
            var mid = Guid.Parse(m.Id!);
            if (foundResult.Contains(mid))
            {
                var r = rights.FirstOrDefault(x => x.Key == Guid.Parse(m.Id!));
                if (r != null)
                {
                    RightMenuItem rmi = new RightMenuItem();
                    rmi.Id = r.Key.ToString();
                    rmi.ParentId = m.ParentId;
                    rmi.Url = m.Url;
                    rmi.Text = m.Text;
                    rmi.Icon = m.Icon;
                    rmi.IsDisabled = m.IsDisabled;
                    rmi.IsActive = m.IsActive;
                    rmi.IsCollapsed = m.IsCollapsed;
                    rmi.Parent = m.Parent;
                    rmi.Target = m.Target;
                    rmi.Match = m.Match;
                    var rs = r.SelectMany(l => l.Rights.Split('┇')).Distinct();
                    rmi.Rights = rs.ToList();
                    newTree.Add(rmi);
                    BuildUserChildTree(allMenus, rmi, foundResult, rights);
                }
                else
                {
                    MenuItem mi = new MenuItem();
                    mi.Id = m.Id;
                    mi.ParentId = m.ParentId;
                    mi.Url = m.Url;
                    mi.Text = m.Text;
                    mi.Icon = m.Icon;
                    mi.IsDisabled = m.IsDisabled;
                    mi.IsActive = m.IsActive;
                    mi.IsCollapsed = m.IsCollapsed;
                    mi.Parent = m.Parent;
                    mi.Target = m.Target;
                    mi.Match = m.Match;
                    newTree.Add(mi);
                    BuildUserChildTree(allMenus, mi, foundResult, rights);
                }
            }
        }

        /// <summary>
        /// 迭代获得用户根以下的目录
        /// </summary>
        /// <param name="allMenus"></param>
        /// <param name="parentM"></param>
        /// <param name="foundResult"></param>
        /// <param name="rights"></param>
        void BuildUserChildTree(List<MenuItem> allMenus, MenuItem parentM, List<Guid> foundResult, IList<IGrouping<Guid, DBLib.SRoleRightsRel>> rights)
        {
            foreach (var m in SiteDescription.GetAllMenusFlat().Where(x => x.ParentId == parentM.Id))
            {
                if (foundResult is not null && foundResult.Contains(Guid.Parse(m.Id!)))
                {
                    var r = rights.FirstOrDefault(x => x.Key == Guid.Parse(m.Id!));
                    if (r != null)
                    {
                        RightMenuItem rmi = new RightMenuItem();
                        rmi.Id = r.Key.ToString();
                        rmi.ParentId = m.ParentId;
                        rmi.Url = m.Url;
                        rmi.Text = m.Text;
                        rmi.Icon = m.Icon;
                        rmi.IsDisabled = m.IsDisabled;
                        rmi.IsActive = m.IsActive;
                        rmi.IsCollapsed = m.IsCollapsed;
                        rmi.Parent = m.Parent;
                        rmi.Target = m.Target;
                        rmi.Match = m.Match;
                        var rs = r.SelectMany(l => l.Rights.Split('┇')).Distinct();
                        rmi.Rights = rs.ToList();
                        var v = parentM.Items.ToList();
                        v.Add(rmi);
                        parentM.Items = v;
                        // 修改：对新创建的rmi进行递归
                        BuildUserChildTree(allMenus, rmi, foundResult, rights);
                    }
                    else
                    {
                        MenuItem mi = new MenuItem();
                        mi.Id = m.Id;
                        mi.ParentId = m.ParentId;
                        mi.Url = m.Url;
                        mi.Text = m.Text;
                        mi.Icon = m.Icon;
                        mi.IsDisabled = m.IsDisabled;
                        mi.IsActive = m.IsActive;
                        mi.IsCollapsed = m.IsCollapsed;
                        mi.Parent = m.Parent;
                        mi.Items = new List<MenuItem>(); // 修改：初始化为空列表
                        mi.Target = m.Target;
                        mi.Match = m.Match;
                        var v = parentM.Items.ToList();
                        v.Add(mi);
                        parentM.Items = v;
                        // 修改：对新创建的mi进行递归
                        BuildUserChildTree(allMenus, mi, foundResult, rights);
                    }
                }
            }
        }
        #endregion

        private void OnLocationChanged(object sender, LocationChangedEventArgs e)
        {
            var targetUri = e.Location; // 获取目标URL
        }

        [Inject]
        protected IConfiguration config { get; set; } = null!;

        public T? GetConfig<T>(string key)
        {
            if (!string.IsNullOrWhiteSpace(key))
            {
                return config.GetValue<T>(key);
            }
            return default(T);
        }

        public bool? _isDebug = null;
        public bool IsDebug
        {
            get
            {
                return _isDebug ??= GetConfig<bool>("Debug");
            }
        }

        //类中注入
        [Inject]
        public IJSRuntime JsRuntime { get; set; } = null!;

        [Inject]
        protected NavigationManager nav { get; set; } = null!;

        /// <summary>
        /// 
        /// </summary>
        [Inject]
        [NotNull]
        public MessageService? MessageService { get; set; }

        public async Task Tip(String msg)
        {
            await MessageService.Show(new MessageOption()
            {
                Content = msg
            });
        }

        public async Task SuccessMsg(String msg)
        {
            await ToastService.Show(new ToastOption()
            {
                Category = ToastCategory.Success,
                Title = "成功",
                Content = msg
            });
        }

        public async Task ErrMsg(String msg)
        {
            await ToastService.Show(new ToastOption()
            {
                Category = ToastCategory.Error,
                Title = "发生错误",
                Content = msg
            });
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                //await JsRuntime.InvokeVoidAsync("$.setWindowsHeight");
            }
            await base.OnAfterRenderAsync(firstRender);
        }

        private bool collapseNavMenu = true;

        private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;

        private void ToggleNavMenu()
        {
            collapseNavMenu = !collapseNavMenu;
        }

        List<string> _currentRights = new List<string>();
        private async Task Nav(MenuItem item)
        {
            Guid? lastMenu = CurrentMenuId;
            var lastRights = _pageRights;
            CurrentMenuId = item.Id.ToNullableGuid();
            _pageRights = new();
            BreadCrumb = string.Join(" / ", GetNavPath(item));
            if(item is RightMenuItem rmi)
            {
                _currentRights = rmi.Rights;
            }
            await SaveLastRights(lastMenu, lastRights);
            //if (!item.Items.Any() && !string.IsNullOrEmpty(item.Text))
            //{
            //    await TitleService.SetTitle($"{item.Text} - {AppLocalizer["Title"]}");
            //}
        }

        async Task SaveLastRights(Guid? lastMenu,List<String> lastRights)
        {
            if(IsDebug && lastMenu.HasValue)
            {
                await SaveRights(lastMenu.Value,lastRights);
            }
        }

        IEnumerable<string> GetNavPath(MenuItem item)
        {
            var parent = SiteDescription.GetAllMenusFlat().FirstOrDefault(x => x.Items.Contains(item));
            if (parent != null)
            {
                foreach (var s in GetNavPath(parent))
                {
                    yield return s;
                }
            }
            yield return item.Text!;
        }

        List<string> _pageRights { get; set; } = new List<string>();

        global::Core.SysUser IMainLayout.CurrentUser => throw new NotImplementedException();

        public void Register(string? right)
        {
            if ((CurrentMenuId.HasValue || IsDebug) && !string.IsNullOrWhiteSpace(right))
            {
                if(!_pageRights.Contains(right))
                {
                    _pageRights.Add(right);
                }
            }
        }

        public async Task<List<string>> GetCurrentRights()
        {
            if (IsDebug || CurrentUser.IsAdmin)
            {
                return _pageRights;
            }
            else
            {
                if ((_currentRights == null || _currentRights.Count == 0) && CurrentMenuId != null)
                {
                    if (Menus == null)
                        await InitMenus();
                    var m = Menus?.AsFlat().FirstOrDefault(x => x.Id == CurrentMenuId.Value.ToString());
                    if (m is RightMenuItem rmi)
                    {
                        _currentRights = rmi.Rights;
                    }
                }
                return _currentRights;
            }
        }

        protected override void OnParametersSet()
        {
            var v = NavigationManager.Uri.Split('/').Last().ToLower();
            if(!string.IsNullOrWhiteSpace(v) && CurrentMenuId == null)
            {
                var id = SiteDescription.GetAllMenusFlat().Where(x => x.Url?.ToLower() == v).Select(x => x.Id).FirstOrDefault();
                if(!string.IsNullOrWhiteSpace(id))
                {
                    CurrentMenuId = Guid.Parse(id);
                }
            }
            base.OnParametersSet();
        }

        private async Task SaveRights(Guid lastMenu, List<String> lastRights)
        {
            try
            {
                using var db = dbFac.CreateDbContext();
                var m = await db.SMenuRights.FirstOrDefaultAsync(x => x.SMenuRightID == lastMenu);
                if (m == null)
                {
                    m = new DBLib.SMenuRights();
                    m.SMenuRightID = lastMenu;
                    db.SMenuRights.Add(m);
                }
                if (lastRights != null && lastRights.Count > 0)
                {
                    m.Rights = String.Join("┇", lastRights);
                }
                else
                {
                    m.Rights = "使用";
                }
                await db.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                var e = ex;
            }
        }


        public async Task<bool> Confirm(string msg)
        {
            var result = await JsRuntime.InvokeAsync<bool>("confirm",new object?[] { msg });
            return result;
        }

        string? GetVersion()
        {
            return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString();
        }

        public void Dispose()
        {
            nav.LocationChanged -= OnLocationChanged;
        }

        public string? GetTitle(string table, string keyId)
        {
            var o = keyId?.ToLower();
            return LookupService.GetItemsByKey(table)?.Where(c => c.Value.ToLower() == o).Select(c => c.Text).FirstOrDefault();
        }
    }
}
以上是Blazor中的Layout页面，说一下改进建议