using MediatR;
using TakeoutSaaS.Application.Identity.Commands;
using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Application.Identity.Handlers;

/// <summary>
/// 克隆租户角色命令处理器。
/// </summary>
public sealed class CloneTenantRoleCommandHandler(
    IRoleRepository roleRepository,
    IRolePermissionRepository rolePermissionRepository)
    : IRequestHandler<CloneTenantRoleCommand, RoleDto>
{
    /// <inheritdoc />
    public async Task<RoleDto> Handle(CloneTenantRoleCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验新角色编码不能为空
        if (string.IsNullOrWhiteSpace(request.NewCode))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "新角色编码不能为空");
        }

        // 2. 校验源角色存在
        var source = await roleRepository.FindByIdAsync(PortalType.Tenant, request.TenantId, request.SourceRoleId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "源角色不存在");

        // 3. 校验新角色编码唯一性（租户内）
        var existing = await roleRepository.FindByCodeAsync(PortalType.Tenant, request.TenantId, request.NewCode, cancellationToken);
        if (existing is not null)
        {
            throw new BusinessException(ErrorCodes.Conflict, $"角色编码 {request.NewCode} 已存在");
        }

        // 4. 构造新角色实体
        var newRole = new Role
        {
            Portal = PortalType.Tenant,
            TenantId = request.TenantId,
            Code = request.NewCode.Trim(),
            Name = string.IsNullOrWhiteSpace(request.Name) ? source.Name : request.Name.Trim(),
            Description = request.Description ?? source.Description
        };

        // 5. 持久化新角色
        await roleRepository.AddAsync(newRole, cancellationToken);
        await roleRepository.SaveChangesAsync(cancellationToken);

        // 6. 复制权限关系
        if (request.CopyPermissions)
        {
            var sourcePermissions = await rolePermissionRepository.GetByRoleIdsAsync(
                PortalType.Tenant,
                request.TenantId,
                [request.SourceRoleId],
                cancellationToken);

            var permissionIds = sourcePermissions.Select(p => p.PermissionId).Distinct().ToArray();
            if (permissionIds.Length > 0)
            {
                await rolePermissionRepository.ReplaceRolePermissionsAsync(
                    PortalType.Tenant,
                    request.TenantId,
                    newRole.Id,
                    permissionIds,
                    cancellationToken);
            }
        }

        // 7. 返回 DTO
        return new RoleDto
        {
            Portal = newRole.Portal,
            Id = newRole.Id,
            TenantId = newRole.TenantId,
            Code = newRole.Code,
            Name = newRole.Name,
            Description = newRole.Description
        };
    }
}
