using OpenWarehouse.auth.api.Common.CustomIdentifyManager;

namespace OpenWarehouse.auth.api.Common.DefaultUserAndRole;

public class DefaultIdentify(
    ILogger<DefaultIdentify> logger,
    SignInManager<ApplicationUser> signInManager,
    RoleManager<ApplicationRole> roleManager,
    UserManager<ApplicationUser> userManager,
    ApplicationDbContext applicationDbContext,
    PrivilageManager.PrivilegeManager privilegeManager,
    IConfiguration configuration)
{
    public async Task SeedAsync()
    {
        if (!await applicationDbContext.RolePrivilages.AnyAsync(x => true))
        {
            var listOfRoles = GlobalPrivilage.GatherPrivilegeStrings();
            foreach (var privilage in listOfRoles)
            {
                var rolePrivilage = new RolePrivilage() { Privilage = privilage };
                applicationDbContext.RolePrivilages.Add(rolePrivilage);
                logger.LogDebug($"Created privilage: {privilage}");
            }

            await applicationDbContext.SaveChangesAsync();
        }
        

        if (!roleManager.Roles.Any())
        {
            ApplicationRole admin = new ApplicationRole()
            {
                Name = "Admin",
                IsGlobalAdmin = true,
            };
            ApplicationRole user = new ApplicationRole()
            {
                Name = "User",
                IsGlobalAdmin = false
            };
            ApplicationRole service = new ApplicationRole()
            {
                Name = "Service",
                IsGlobalAdmin = true
            };
            if ((await roleManager.CreateAsync(admin)).Succeeded)
            {
                logger.LogDebug($"Created role {admin}");
            }
            else
            {
                logger.LogWarning($"Unable create role {admin}");
            }
            if ((await roleManager.CreateAsync(user)).Succeeded)
            {
                logger.LogDebug($"Created role {user.Name}");
            }
            else
            {
                logger.LogWarning($"Unable create role {user.Name}");
            }
            if ((await roleManager.CreateAsync(service)).Succeeded)
            {
                logger.LogDebug($"Created role {service.Name}");
            }
            else
            {
                logger.LogWarning($"Unable create role {service.Name}");
            }
        }

        if (!userManager.Users.Any())
        {
            var username = configuration["SuperUser:Name"] ?? "Admin";
            var email = configuration["SuperUser:Email"] ?? "Admin@admin.local";
            
            var password = configuration["SuperUser:Password"] ?? GenerateRandomPass(10);
            
            
            var user = new ApplicationUser() { UserName = username, Email = email, EmailConfirmed = true};
            var userResult = (await userManager.CreateAsync(user, password));
            if (userResult.Succeeded)
            {
                var claimResult = await userManager.AddClaimAsync(user, AccountType.Admin.Claim());

                if (claimResult.Succeeded)
                {
                    logger.LogInformation($"Sucess added claim {AccountType.Admin.Claim()} to user {user.UserName}.");
                }
                else
                {
                    logger.LogWarning($"Unable added claim {AccountType.Admin.Claim()} to user {user.UserName}.");
                }
                
                logger.LogInformation($"Created user, Name: {user.UserName} Email: {user.Email}, Password: {password}");
                var roleResult = (await userManager.AddToRoleAsync(user, "Admin"));
                if (roleResult.Succeeded)
                {
                    logger.LogInformation($"Added role Admin to {user.UserName}");
                }
                else
                {
                    logger.LogWarning($"Unable added role Admin to user {user.UserName}");
                }
            }
            else
            {
                logger.LogWarning($"Unable create user {user.UserToken}. Messs: {string.Join(";",userResult.Errors)}");
            }

            return;
        }
    }
    
    private string GenerateRandomPass(int length)
    {
        const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const string lower = "abcdefghijklmnopqrstuvwxyz";
        const string digits = "0123456789";
        const string specialChars = "!@#$%^&*()_+{}\":'<>?[];,./";

        var allChars = upper + lower + digits + specialChars;
        var random = new Random();
        var passwordChars = new char[length];
        
        passwordChars[0] = upper[random.Next(upper.Length)];
        passwordChars[1] = lower[random.Next(lower.Length)];
        passwordChars[2] = digits[random.Next(digits.Length)];
        passwordChars[3] = specialChars[random.Next(specialChars.Length)];
        
        for (int i = 4; i < length; i++)
        {
            passwordChars[i] = allChars[random.Next(allChars.Length)];
        }
        
        return new string(passwordChars.OrderBy(c => random.Next()).ToArray());
    }
}