using HoneyBox.Admin.Data;
using HoneyBox.Admin.Entities;
using HoneyBox.Admin.Models.Common;
using HoneyBox.Admin.Models.Menu;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Admin.Services;

/// <summary>
/// 菜单服务实现
/// </summary>
public class MenuService : IMenuService
{
    private readonly AdminDbContext _dbContext;
    private readonly ILogger<MenuService> _logger;

    public MenuService(AdminDbContext dbContext, ILogger<MenuService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<List<MenuTreeDto>> GetMenuTreeAsync()
    {
        var menus = await _dbContext.Menus
            .OrderBy(m => m.SortOrder)
            .ThenBy(m => m.Id)
            .ToListAsync();

        return BuildMenuTree(menus, 0);
    }

    /// <inheritdoc />
    public async Task<MenuDto> GetByIdAsync(long id)
    {
        var menu = await _dbContext.Menus.FindAsync(id);
        if (menu == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "菜单不存在");
        }

        return MapToDto(menu);
    }

    /// <inheritdoc />
    public async Task<long> CreateAsync(CreateMenuRequest request)
    {
        // 验证父菜单是否存在
        if (request.ParentId > 0)
        {
            var parentExists = await _dbContext.Menus.AnyAsync(m => m.Id == request.ParentId);
            if (!parentExists)
            {
                throw new AdminException(AdminErrorCodes.InvalidParameter, "父菜单不存在");
            }
        }

        var menu = new Entities.Menu
        {
            ParentId = request.ParentId,
            Name = request.Name,
            Path = request.Path,
            Component = request.Component,
            Icon = request.Icon,
            MenuType = request.MenuType,
            Permission = request.Permission,
            SortOrder = request.SortOrder,
            Status = request.Status,
            IsExternal = request.IsExternal,
            IsCache = request.IsCache,
            CreatedAt = DateTime.Now
        };

        _dbContext.Menus.Add(menu);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("创建菜单成功: {MenuId} - {MenuName}", menu.Id, menu.Name);
        return menu.Id;
    }


    /// <inheritdoc />
    public async Task UpdateAsync(long id, UpdateMenuRequest request)
    {
        var menu = await _dbContext.Menus.FindAsync(id);
        if (menu == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "菜单不存在");
        }

        // 验证父菜单是否存在
        if (request.ParentId > 0)
        {
            // 不能将自己设为父菜单
            if (request.ParentId == id)
            {
                throw new AdminException(AdminErrorCodes.InvalidParameter, "不能将菜单设为自己的子菜单");
            }

            var parentExists = await _dbContext.Menus.AnyAsync(m => m.Id == request.ParentId);
            if (!parentExists)
            {
                throw new AdminException(AdminErrorCodes.InvalidParameter, "父菜单不存在");
            }

            // 检查是否会形成循环引用（不能将菜单设为其子孙菜单的子菜单）
            if (await IsDescendantAsync(request.ParentId, id))
            {
                throw new AdminException(AdminErrorCodes.InvalidParameter, "不能将菜单设为其子菜单的子菜单");
            }
        }

        menu.ParentId = request.ParentId;
        menu.Name = request.Name;
        menu.Path = request.Path;
        menu.Component = request.Component;
        menu.Icon = request.Icon;
        menu.MenuType = request.MenuType;
        menu.Permission = request.Permission;
        menu.SortOrder = request.SortOrder;
        menu.Status = request.Status;
        menu.IsExternal = request.IsExternal;
        menu.IsCache = request.IsCache;
        menu.UpdatedAt = DateTime.Now;

        await _dbContext.SaveChangesAsync();
        _logger.LogInformation("更新菜单成功: {MenuId} - {MenuName}", menu.Id, menu.Name);
    }

    /// <inheritdoc />
    public async Task DeleteAsync(long id)
    {
        var menu = await _dbContext.Menus.FindAsync(id);
        if (menu == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "菜单不存在");
        }

        // 检查是否有子菜单
        var hasChildren = await _dbContext.Menus.AnyAsync(m => m.ParentId == id);
        if (hasChildren)
        {
            throw new AdminException(AdminErrorCodes.MenuHasChildren, "该菜单下有子菜单，无法删除");
        }

        // 删除关联数据
        var roleMenus = await _dbContext.RoleMenus.Where(rm => rm.MenuId == id).ToListAsync();
        _dbContext.RoleMenus.RemoveRange(roleMenus);

        var departmentMenus = await _dbContext.DepartmentMenus.Where(dm => dm.MenuId == id).ToListAsync();
        _dbContext.DepartmentMenus.RemoveRange(departmentMenus);

        var userMenus = await _dbContext.AdminUserMenus.Where(um => um.MenuId == id).ToListAsync();
        _dbContext.AdminUserMenus.RemoveRange(userMenus);

        _dbContext.Menus.Remove(menu);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("删除菜单成功: {MenuId} - {MenuName}", id, menu.Name);
    }

    /// <inheritdoc />
    public async Task<List<MenuTreeDto>> GetUserMenusAsync(long adminUserId)
    {
        // 获取用户信息
        var user = await _dbContext.AdminUsers
            .Include(u => u.AdminUserRoles)
            .FirstOrDefaultAsync(u => u.Id == adminUserId);

        if (user == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "用户不存在");
        }

        var menuIds = new HashSet<long>();

        // 1. 获取用户部门的菜单
        if (user.DepartmentId.HasValue)
        {
            var departmentMenuIds = await _dbContext.DepartmentMenus
                .Where(dm => dm.DepartmentId == user.DepartmentId.Value)
                .Select(dm => dm.MenuId)
                .ToListAsync();
            foreach (var menuId in departmentMenuIds)
            {
                menuIds.Add(menuId);
            }
        }

        // 2. 获取用户角色的菜单
        var roleIds = user.AdminUserRoles.Select(ur => ur.RoleId).ToList();
        if (roleIds.Any())
        {
            var roleMenuIds = await _dbContext.RoleMenus
                .Where(rm => roleIds.Contains(rm.RoleId))
                .Select(rm => rm.MenuId)
                .ToListAsync();
            foreach (var menuId in roleMenuIds)
            {
                menuIds.Add(menuId);
            }
        }

        // 3. 获取用户专属菜单
        var userMenuIds = await _dbContext.AdminUserMenus
            .Where(um => um.AdminUserId == adminUserId)
            .Select(um => um.MenuId)
            .ToListAsync();
        foreach (var menuId in userMenuIds)
        {
            menuIds.Add(menuId);
        }

        // 获取所有菜单并过滤
        var menus = await _dbContext.Menus
            .Where(m => menuIds.Contains(m.Id) && m.Status == 1)
            .OrderBy(m => m.SortOrder)
            .ThenBy(m => m.Id)
            .ToListAsync();

        // 补充父菜单（确保树形结构完整）
        var allMenuIds = menus.Select(m => m.Id).ToHashSet();
        var parentIds = menus.Select(m => m.ParentId).Where(pid => pid > 0 && !allMenuIds.Contains(pid)).ToList();
        
        while (parentIds.Any())
        {
            var parentMenus = await _dbContext.Menus
                .Where(m => parentIds.Contains(m.Id))
                .ToListAsync();
            
            menus.AddRange(parentMenus);
            allMenuIds = menus.Select(m => m.Id).ToHashSet();
            parentIds = parentMenus.Select(m => m.ParentId).Where(pid => pid > 0 && !allMenuIds.Contains(pid)).ToList();
        }

        // 重新排序
        menus = menus.OrderBy(m => m.SortOrder).ThenBy(m => m.Id).ToList();

        return BuildMenuTree(menus, 0);
    }

    /// <summary>
    /// 构建菜单树
    /// </summary>
    private List<MenuTreeDto> BuildMenuTree(List<Entities.Menu> menus, long parentId)
    {
        return menus
            .Where(m => m.ParentId == parentId)
            .Select(m => new MenuTreeDto
            {
                Id = m.Id,
                ParentId = m.ParentId,
                Name = m.Name,
                Path = m.Path,
                Component = m.Component,
                Icon = m.Icon,
                MenuType = m.MenuType,
                Permission = m.Permission,
                SortOrder = m.SortOrder,
                Status = m.Status,
                IsExternal = m.IsExternal,
                IsCache = m.IsCache,
                Children = BuildMenuTree(menus, m.Id)
            })
            .ToList();
    }

    /// <summary>
    /// 检查 targetId 是否是 menuId 的子孙菜单
    /// </summary>
    private async Task<bool> IsDescendantAsync(long targetId, long menuId)
    {
        var children = await _dbContext.Menus
            .Where(m => m.ParentId == menuId)
            .Select(m => m.Id)
            .ToListAsync();

        if (children.Contains(targetId))
        {
            return true;
        }

        foreach (var childId in children)
        {
            if (await IsDescendantAsync(targetId, childId))
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 映射实体到 DTO
    /// </summary>
    private static MenuDto MapToDto(Entities.Menu menu)
    {
        return new MenuDto
        {
            Id = menu.Id,
            ParentId = menu.ParentId,
            Name = menu.Name,
            Path = menu.Path,
            Component = menu.Component,
            Icon = menu.Icon,
            MenuType = menu.MenuType,
            Permission = menu.Permission,
            SortOrder = menu.SortOrder,
            Status = menu.Status,
            IsExternal = menu.IsExternal,
            IsCache = menu.IsCache,
            CreatedAt = menu.CreatedAt,
            UpdatedAt = menu.UpdatedAt
        };
    }
}
