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

namespace HoneyBox.Admin.Services;

/// <summary>
/// 部门服务实现
/// </summary>
public class DepartmentService : IDepartmentService
{
    private readonly AdminDbContext _dbContext;
    private readonly ILogger<DepartmentService> _logger;

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

    /// <inheritdoc />
    public async Task<List<DepartmentTreeDto>> GetDepartmentTreeAsync()
    {
        var departments = await _dbContext.Departments
            .Include(d => d.AdminUsers)
            .OrderBy(d => d.SortOrder)
            .ThenBy(d => d.Id)
            .ToListAsync();

        return BuildDepartmentTree(departments, 0);
    }

    /// <inheritdoc />
    public async Task<DepartmentDto> GetByIdAsync(long id)
    {
        var department = await _dbContext.Departments
            .Include(d => d.DepartmentMenus)
            .FirstOrDefaultAsync(d => d.Id == id);

        if (department == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "部门不存在");
        }

        return new DepartmentDto
        {
            Id = department.Id,
            ParentId = department.ParentId,
            Name = department.Name,
            Code = department.Code,
            Description = department.Description,
            SortOrder = department.SortOrder,
            Status = department.Status,
            CreatedAt = department.CreatedAt,
            UpdatedAt = department.UpdatedAt,
            MenuIds = department.DepartmentMenus.Select(dm => dm.MenuId).ToList()
        };
    }

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

        // 检查编码是否重复
        if (!string.IsNullOrWhiteSpace(request.Code))
        {
            var codeExists = await _dbContext.Departments.AnyAsync(d => d.Code == request.Code);
            if (codeExists)
            {
                throw new AdminException(AdminErrorCodes.DuplicateDepartmentCode, "部门编码已存在");
            }
        }

        var department = new Entities.Department
        {
            ParentId = request.ParentId,
            Name = request.Name,
            Code = request.Code,
            Description = request.Description,
            SortOrder = request.SortOrder,
            Status = request.Status,
            CreatedAt = DateTime.Now
        };

        _dbContext.Departments.Add(department);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("创建部门成功: {DepartmentId} - {DepartmentName}", department.Id, department.Name);
        return department.Id;
    }


    /// <inheritdoc />
    public async Task UpdateAsync(long id, UpdateDepartmentRequest request)
    {
        var department = await _dbContext.Departments.FindAsync(id);
        if (department == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "部门不存在");
        }

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

            var parentExists = await _dbContext.Departments.AnyAsync(d => d.Id == request.ParentId);
            if (!parentExists)
            {
                throw new AdminException(AdminErrorCodes.InvalidParameter, "父部门不存在");
            }

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

        // 检查编码是否重复（排除自己）
        if (!string.IsNullOrWhiteSpace(request.Code))
        {
            var codeExists = await _dbContext.Departments.AnyAsync(d => d.Code == request.Code && d.Id != id);
            if (codeExists)
            {
                throw new AdminException(AdminErrorCodes.DuplicateDepartmentCode, "部门编码已存在");
            }
        }

        department.ParentId = request.ParentId;
        department.Name = request.Name;
        department.Code = request.Code;
        department.Description = request.Description;
        department.SortOrder = request.SortOrder;
        department.Status = request.Status;
        department.UpdatedAt = DateTime.Now;

        await _dbContext.SaveChangesAsync();
        _logger.LogInformation("更新部门成功: {DepartmentId} - {DepartmentName}", department.Id, department.Name);
    }

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

        // 检查是否有子部门
        var hasChildren = await _dbContext.Departments.AnyAsync(d => d.ParentId == id);
        if (hasChildren)
        {
            throw new AdminException(AdminErrorCodes.DepartmentHasChildren, "该部门下有子部门，无法删除");
        }

        // 检查是否有用户
        var hasUsers = await _dbContext.AdminUsers.AnyAsync(u => u.DepartmentId == id);
        if (hasUsers)
        {
            throw new AdminException(AdminErrorCodes.DepartmentHasUsers, "该部门下有用户，无法删除");
        }

        // 删除关联数据
        var departmentMenus = await _dbContext.DepartmentMenus.Where(dm => dm.DepartmentId == id).ToListAsync();
        _dbContext.DepartmentMenus.RemoveRange(departmentMenus);

        _dbContext.Departments.Remove(department);
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("删除部门成功: {DepartmentId} - {DepartmentName}", id, department.Name);
    }

    /// <inheritdoc />
    public async Task<List<long>> GetMenuIdsAsync(long departmentId)
    {
        var department = await _dbContext.Departments.FindAsync(departmentId);
        if (department == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "部门不存在");
        }

        return await _dbContext.DepartmentMenus
            .Where(dm => dm.DepartmentId == departmentId)
            .Select(dm => dm.MenuId)
            .ToListAsync();
    }

    /// <inheritdoc />
    public async Task AssignMenusAsync(long departmentId, List<long> menuIds)
    {
        var department = await _dbContext.Departments.FindAsync(departmentId);
        if (department == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "部门不存在");
        }

        // 删除现有关联
        var existingMenus = await _dbContext.DepartmentMenus.Where(dm => dm.DepartmentId == departmentId).ToListAsync();
        _dbContext.DepartmentMenus.RemoveRange(existingMenus);

        // 添加新关联
        if (menuIds.Any())
        {
            var newMenus = menuIds.Distinct().Select(menuId => new DepartmentMenu
            {
                DepartmentId = departmentId,
                MenuId = menuId
            });
            _dbContext.DepartmentMenus.AddRange(newMenus);
        }

        await _dbContext.SaveChangesAsync();
        _logger.LogInformation("部门 {DepartmentId} 分配菜单成功，菜单数量: {Count}", departmentId, menuIds.Count);
    }

    /// <inheritdoc />
    public async Task<List<AdminUserDto>> GetDepartmentUsersAsync(long departmentId)
    {
        var department = await _dbContext.Departments.FindAsync(departmentId);
        if (department == null)
        {
            throw new AdminException(AdminErrorCodes.InvalidParameter, "部门不存在");
        }

        return await _dbContext.AdminUsers
            .Where(u => u.DepartmentId == departmentId)
            .Include(u => u.AdminUserRoles)
                .ThenInclude(ur => ur.Role)
            .Select(u => new AdminUserDto
            {
                Id = u.Id,
                Username = u.Username,
                RealName = u.RealName,
                Avatar = u.Avatar,
                Email = u.Email,
                Phone = u.Phone,
                DepartmentId = u.DepartmentId,
                DepartmentName = department.Name,
                Status = u.Status,
                LastLoginTime = u.LastLoginTime,
                LastLoginIp = u.LastLoginIp,
                CreatedAt = u.CreatedAt,
                UpdatedAt = u.UpdatedAt,
                Remark = u.Remark,
                RoleIds = u.AdminUserRoles.Select(ur => ur.RoleId).ToList(),
                RoleNames = u.AdminUserRoles.Select(ur => ur.Role.Name).ToList()
            })
            .ToListAsync();
    }

    /// <summary>
    /// 构建部门树
    /// </summary>
    private List<DepartmentTreeDto> BuildDepartmentTree(List<Entities.Department> departments, long parentId)
    {
        return departments
            .Where(d => d.ParentId == parentId)
            .Select(d => new DepartmentTreeDto
            {
                Id = d.Id,
                ParentId = d.ParentId,
                Name = d.Name,
                Code = d.Code,
                SortOrder = d.SortOrder,
                Status = d.Status,
                UserCount = d.AdminUsers.Count,
                Children = BuildDepartmentTree(departments, d.Id)
            })
            .ToList();
    }

    /// <summary>
    /// 检查 targetId 是否是 departmentId 的子孙部门
    /// </summary>
    private async Task<bool> IsDescendantAsync(long targetId, long departmentId)
    {
        var children = await _dbContext.Departments
            .Where(d => d.ParentId == departmentId)
            .Select(d => d.Id)
            .ToListAsync();

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

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

        return false;
    }
}
