using MediatR;
using System.Text.Json;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Application.Identity.Commands;
using TakeoutSaaS.Application.Identity.Contracts;
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;

namespace TakeoutSaaS.Application.Identity.Handlers;

/// <summary>
/// 生成用户重置密码链接处理器。
/// </summary>
public sealed class ResetIdentityUserPasswordCommandHandler(
    IAdminPasswordResetTokenStore tokenStore,
    IIdentityUserRepository identityUserRepository,
    ICurrentUserAccessor currentUserAccessor,
    IAdminAuthService adminAuthService,
    IIdentityOperationLogPublisher operationLogPublisher)
    : IRequestHandler<ResetIdentityUserPasswordCommand, ResetIdentityUserPasswordResult>
{
    /// <inheritdoc />
    public async Task<ResetIdentityUserPasswordResult> Handle(ResetIdentityUserPasswordCommand request, CancellationToken cancellationToken)
    {
        // 1. 获取操作者档案（用于操作日志）
        var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);

        // 2. (空行后) 查询用户实体
        var user = await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
        if (user == null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "用户不存在");
        }

        // 3. (空行后) 限定仅允许重置平台管理员账号
        if (user.Portal != PortalType.Admin || user.TenantId is not null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "用户不存在");
        }

        // 4. (空行后) 签发重置令牌（1 小时有效）
        var expiresAt = DateTime.UtcNow.AddHours(1);
        var token = await tokenStore.IssueAsync(user.Id, expiresAt, cancellationToken);

        // 5. (空行后) 标记用户需重置密码
        user.MustChangePassword = true;
        user.FailedLoginCount = 0;
        user.LockedUntil = null;
        if (user.Status == IdentityUserStatus.Locked)
        {
            user.Status = IdentityUserStatus.Active;
        }

        // 6. (空行后) 构建操作日志消息
        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:password-reset",
            TargetType = "identity_user",
            TargetIds = JsonSerializer.Serialize(new[] { user.Id }),
            OperatorId = currentUserAccessor.UserId.ToString(),
            OperatorName = operatorName,
            Parameters = JsonSerializer.Serialize(new { userId = user.Id, portal = PortalType.Admin.ToString() }),
            Result = JsonSerializer.Serialize(new { userId = user.Id, expiresAt }),
            Success = true
        };

        // 7. (空行后) 写入 Outbox 并保存变更
        await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
        await identityUserRepository.SaveChangesAsync(cancellationToken);

        return new ResetIdentityUserPasswordResult
        {
            Token = token,
            ExpiresAt = expiresAt
        };
    }
}
