using MediatR;
using Microsoft.AspNetCore.Identity;
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.Application.Identity.Queries;
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;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.Identity.Handlers;

/// <summary>
/// 创建用户处理器。
/// </summary>
public sealed class CreateIdentityUserCommandHandler(
    IIdentityUserRepository identityUserRepository,
    IUserRoleRepository userRoleRepository,
    IRoleRepository roleRepository,
    IPasswordHasher<IdentityUser> passwordHasher,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor currentUserAccessor,
    IAdminAuthService adminAuthService,
    IIdentityOperationLogPublisher operationLogPublisher,
    IIdGenerator idGenerator,
    IMediator mediator)
    : IRequestHandler<CreateIdentityUserCommand, UserDetailDto>
{
    /// <inheritdoc />
    public async Task<UserDetailDto> Handle(CreateIdentityUserCommand 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 tenantId = currentTenantId;
        var account = request.Account.Trim();
        var displayName = request.DisplayName.Trim();
        var phone = string.IsNullOrWhiteSpace(request.Phone) ? null : request.Phone.Trim();
        var email = string.IsNullOrWhiteSpace(request.Email) ? null : request.Email.Trim();
        var roleIds = ParseIds(request.RoleIds, "角色");

        // 4. 唯一性校验
        if (await identityUserRepository.ExistsByAccountAsync(tenantId, account, null, cancellationToken))
        {
            throw new BusinessException(ErrorCodes.Conflict, "账号已存在");
        }

        if (!string.IsNullOrWhiteSpace(phone)
            && await identityUserRepository.ExistsByPhoneAsync(tenantId, phone, null, cancellationToken))
        {
            throw new BusinessException(ErrorCodes.Conflict, "手机号已存在");
        }

        if (!string.IsNullOrWhiteSpace(email)
            && await identityUserRepository.ExistsByEmailAsync(tenantId, email, null, cancellationToken))
        {
            throw new BusinessException(ErrorCodes.Conflict, "邮箱已存在");
        }

        // 5. 校验角色合法性
        if (roleIds.Length > 0)
        {
            var roles = await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
            if (roles.Count != roleIds.Length)
            {
                throw new BusinessException(ErrorCodes.BadRequest, "角色列表包含无效项");
            }
        }

        // 6. 创建用户实体
        var user = new IdentityUser
        {
            Id = idGenerator.NextId(),
            TenantId = tenantId,
            Account = account,
            DisplayName = displayName,
            Phone = phone,
            Email = email,
            Avatar = string.IsNullOrWhiteSpace(request.Avatar) ? null : request.Avatar.Trim(),
            Status = request.Status ?? IdentityUserStatus.Active,
            FailedLoginCount = 0,
            LockedUntil = null,
            LastLoginAt = null,
            MustChangePassword = false,
            PasswordHash = string.Empty
        };
        user.PasswordHash = passwordHasher.HashPassword(user, request.Password);

        // 7. 构建操作日志消息
        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:create",
            TargetType = "identity_user",
            TargetIds = JsonSerializer.Serialize(new[] { user.Id }),
            OperatorId = currentUserAccessor.UserId.ToString(),
            OperatorName = operatorName,
            Parameters = JsonSerializer.Serialize(new
            {
                tenantId,
                account,
                displayName,
                phone,
                email,
                roleIds
            }),
            Result = JsonSerializer.Serialize(new { userId = user.Id }),
            Success = true
        };

        // 8. 持久化用户并写入 Outbox
        await identityUserRepository.AddAsync(user, cancellationToken);
        await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
        await identityUserRepository.SaveChangesAsync(cancellationToken);

        // 9. 绑定角色
        if (roleIds.Length > 0)
        {
            await userRoleRepository.ReplaceUserRolesAsync(tenantId, user.Id, roleIds, cancellationToken);
        }

        // 10. 返回用户详情
        var detail = await mediator.Send(new GetIdentityUserDetailQuery { UserId = user.Id }, cancellationToken);
        return detail ?? new UserDetailDto
        {
            UserId = user.Id,
            TenantId = user.TenantId,
            MerchantId = user.MerchantId,
            Account = user.Account,
            DisplayName = user.DisplayName,
            Phone = user.Phone,
            Email = user.Email,
            Status = user.Status,
            IsLocked = false,
            Roles = Array.Empty<string>(),
            RoleIds = Array.Empty<string>(),
            Permissions = Array.Empty<string>(),
            CreatedAt = user.CreatedAt,
            LastLoginAt = user.LastLoginAt,
            Avatar = user.Avatar,
            RowVersion = user.RowVersion
        };
    }

    private static long[] ParseIds(string[] values, string name)
    {
        // 1. 空数组直接返回
        if (values.Length == 0)
        {
            return Array.Empty<long>();
        }

        // 2. 解析并去重
        var ids = new List<long>(values.Length);
        foreach (var value in values)
        {
            if (!long.TryParse(value, out var id) || id <= 0)
            {
                throw new BusinessException(ErrorCodes.BadRequest, $"{name} ID 无效");
            }

            ids.Add(id);
        }

        // 3. 返回去重结果
        return ids.Distinct().ToArray();
    }
}
