using Indotalent.ConfigBackEnd.Interfaces;
using Indotalent.Data.Entities;
using Indotalent.Infrastructure.Authorization.Identity;
using Indotalent.Infrastructure.Database;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace Indotalent.Features.Setting.SystemUser.Cqrs;

public class CreateSystemUserRequest
{
    public string? FullName { get; set; }
    public string? Email { get; set; }
    public string? Password { get; set; }
    public string? PhoneNumber { get; set; }
    public string? UserName { get; set; }
    public bool EmailConfirmed { get; set; }
    public bool PhoneNumberConfirmed { get; set; }
    public bool TwoFactorEnabled { get; set; }
    public bool IsActive { get; set; }
    public bool LockoutEnabled { get; set; }
    public DateTimeOffset? LockoutEnd { get; set; }
    public string? SsoIdFirebase { get; set; }
    public string? SsoIdKeycloak { get; set; }
    public string? SsoIdAzure { get; set; }
    public string? SsoIdAws { get; set; }
    public string? SsoIdOther1 { get; set; }
    public string? SsoIdOther2 { get; set; }
    public string? SsoIdOther3 { get; set; }
}

public class CreateSystemUserResponse
{
    public string? Id { get; set; }
    public string? Email { get; set; }
}

public record CreateSystemUserCommand(CreateSystemUserRequest Data) : IRequest<CreateSystemUserResponse>;

public class CreateSystemUserHandler : IRequestHandler<CreateSystemUserCommand, CreateSystemUserResponse>
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly AppDbContext _context;
    private readonly ICurrentUserService _currentUserService;

    public CreateSystemUserHandler(
        UserManager<ApplicationUser> userManager,
        AppDbContext context,
        ICurrentUserService currentUserService)
    {
        _userManager = userManager;
        _context = context;
        _currentUserService = currentUserService;
    }

    public async Task<CreateSystemUserResponse> Handle(CreateSystemUserCommand request, CancellationToken cancellationToken)
    {
        var user = new ApplicationUser
        {
            FullName = request.Data.FullName,
            Email = request.Data.Email,
            UserName = request.Data.Email,
            PhoneNumber = request.Data.PhoneNumber,
            EmailConfirmed = request.Data.EmailConfirmed,
            PhoneNumberConfirmed = request.Data.PhoneNumberConfirmed,
            TwoFactorEnabled = request.Data.TwoFactorEnabled,
            IsActive = request.Data.IsActive,
            LockoutEnabled = request.Data.LockoutEnabled,
            LockoutEnd = request.Data.LockoutEnd,
            SsoIdFirebase = request.Data.SsoIdFirebase,
            SsoIdKeycloak = request.Data.SsoIdKeycloak,
            SsoIdAzure = request.Data.SsoIdAzure,
            SsoIdAws = request.Data.SsoIdAws,
            SsoIdOther1 = request.Data.SsoIdOther1,
            SsoIdOther2 = request.Data.SsoIdOther2,
            SsoIdOther3 = request.Data.SsoIdOther3,
            CreatedAt = DateTime.Now
        };

        var result = await _userManager.CreateAsync(user, request.Data.Password ?? "123456");

        if (!result.Succeeded)
        {
            var errors = string.Join(", ", result.Errors.Select(e => e.Description));
            throw new Exception(errors);
        }

        await _userManager.AddToRoleAsync(user, ApplicationRoles.Member);

        // Automatically map the new user to the current user's tenant
        var tenantId = _currentUserService.TenantId;
        if (!string.IsNullOrEmpty(tenantId))
        {
            var isMapped = await _context.Set<TenantUser>()
                .AnyAsync(tu => tu.TenantId == tenantId && tu.UserId == user.Id, cancellationToken);

            if (!isMapped)
            {
                var tenantUser = new TenantUser
                {
                    TenantId = tenantId,
                    UserId = user.Id,
                    Summary = $"Created by {_currentUserService.UserName ?? _currentUserService.Email}",
                    IsActive = true
                };

                await _context.Set<TenantUser>().AddAsync(tenantUser, cancellationToken);
                await _context.SaveChangesAsync(cancellationToken);
            }
        }

        return new CreateSystemUserResponse { Id = user.Id, Email = user.Email };
    }
}
