using MediatR;
using System.Text.Json;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Application.Identity.Commands;
using TakeoutSaaS.Application.Identity.Events;
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.Identity.Handlers;

/// <summary>
/// 删除用户处理器。
/// </summary>
public sealed class DeleteIdentityUserCommandHandler(
    IIdentityUserRepository identityUserRepository,
    IUserRoleRepository userRoleRepository,
    IRoleRepository roleRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor currentUserAccessor,
    IAdminAuthService adminAuthService,
    IIdentityOperationLogPublisher operationLogPublisher)
    : IRequestHandler<DeleteIdentityUserCommand, bool>
{
    /// <inheritdoc />
    public async Task<bool> Handle(DeleteIdentityUserCommand request, CancellationToken cancellationToken)
    {
        // 1. 获取当前租户与操作者档案
        var currentTenantId = tenantProvider.GetCurrentTenantId();
        var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);

        // 2. 校验跨租户访问
        if (request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
        {
            throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户删除用户");
        }

        // 3. 查询用户实体
        var user = await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
        if (user == null)
        {
            return false;
        }

        if (user.TenantId != currentTenantId)
        {
            return false;
        }

        // 4. 校验租户管理员保留规则
        if (user.Status == IdentityUserStatus.Active)
        {
            await EnsureNotLastActiveTenantAdminAsync(user.TenantId, user.Id, cancellationToken);
        }

        // 5. 构建操作日志消息
        var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
            ? operatorProfile.Account
            : operatorProfile.DisplayName;
        if (string.IsNullOrWhiteSpace(operatorName))
        {
            operatorName = $"user:{currentUserAccessor.UserId}";
        }

        var logMessage = new IdentityUserOperationLogMessage
        {
            OperationType = "identity-user:delete",
            TargetType = "identity_user",
            TargetIds = JsonSerializer.Serialize(new[] { user.Id }),
            OperatorId = currentUserAccessor.UserId.ToString(),
            OperatorName = operatorName,
            Parameters = JsonSerializer.Serialize(new { userId = user.Id, tenantId = user.TenantId }),
            Result = JsonSerializer.Serialize(new { userId = user.Id }),
            Success = true
        };

        // 6. 软删除用户并写入 Outbox
        await identityUserRepository.RemoveAsync(user, cancellationToken);
        await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
        await identityUserRepository.SaveChangesAsync(cancellationToken);

        return true;
    }

    private async Task EnsureNotLastActiveTenantAdminAsync(long tenantId, long userId, CancellationToken cancellationToken)
    {
        // 1. 获取租户管理员角色
        var tenantAdminRole = await roleRepository.FindByCodeAsync("tenant-admin", tenantId, cancellationToken);
        if (tenantAdminRole == null)
        {
            return;
        }

        // 2. 判断用户是否为租户管理员
        var relations = await userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
        if (!relations.Any(x => x.RoleId == tenantAdminRole.Id))
        {
            return;
        }

        // 3. 统计活跃管理员数量
        var filter = new IdentityUserSearchFilter
        {
            TenantId = tenantId,
            RoleId = tenantAdminRole.Id,
            Status = IdentityUserStatus.Active,
            IncludeDeleted = false,
            Page = 1,
            PageSize = 1
        };
        var result = await identityUserRepository.SearchPagedAsync(filter, cancellationToken);
        if (result.Total <= 1)
        {
            throw new BusinessException(ErrorCodes.Conflict, "至少保留一个管理员");
        }
    }
}
