using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace Hcs.WebApp.Data.Identity
{
    public class AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options) : IdentityDbContext<AppUser, AppRole, string>(options)
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSeeding((context, _) =>
                {
                    var adminRole = context.Set<AppRole>().FirstOrDefault(x => x.Name == AppRole.ADMINISTRATOR_TYPE);
                    if (adminRole == null)
                    {
                        adminRole = new AppRole()
                        {
                            Name = AppRole.ADMINISTRATOR_TYPE,
                            NormalizedName = AppRole.ADMINISTRATOR_TYPE.Normalize(),
                            Priority = 0
                        };
                        context.Set<AppRole>().Add(adminRole);
                    }

                    var operatorRole = context.Set<AppRole>().FirstOrDefault(x => x.Name == AppRole.OPERATOR_TYPE);
                    if (operatorRole == null)
                    {
                        context.Set<AppRole>().Add(new AppRole()
                        {
                            Name = AppRole.OPERATOR_TYPE,
                            NormalizedName = AppRole.OPERATOR_TYPE.Normalize(),
                            Priority = 10
                        });
                    }

                    var observerRole = context.Set<AppRole>().FirstOrDefault(x => x.Name == AppRole.OBSERVER_TYPE);
                    if (observerRole == null)
                    {
                        context.Set<AppRole>().Add(new AppRole()
                        {
                            Name = AppRole.OBSERVER_TYPE,
                            NormalizedName = AppRole.OBSERVER_TYPE.Normalize(),
                            Priority = 100
                        });
                    }

                    var adminUser = context.Set<AppUser>().FirstOrDefault(x => x.UserName == AppUser.ADMINISTRATOR_USER_NAME);
                    var hasAdmin = adminUser != null;
                    if (adminUser == null)
                    {
                        adminUser = new AppUser()
                        {
                            UserName = AppUser.ADMINISTRATOR_USER_NAME,
                            NormalizedUserName = AppUser.ADMINISTRATOR_USER_NAME.Normalize(),
                            LockoutEnabled = true
                        };

                        var passwordHasher = new PasswordHasher<AppUser>();
                        adminUser.PasswordHash = passwordHasher.HashPassword(adminUser, AppUser.ADMINISTRATOR_PASSWORD);

                        var entry = context.Set<AppUser>().Add(adminUser);
                    }

                    context.SaveChanges();

                    if (!hasAdmin)
                    {
                        context.Set<IdentityUserRole<string>>().Add(new IdentityUserRole<string>()
                        {
                            UserId = adminUser.Id,
                            RoleId = adminRole.Id
                        });
                    }

                    context.SaveChanges();
                })
                .UseAsyncSeeding(async (context, _, cancellationToken) =>
                {
                    var adminRole = await context.Set<AppRole>().FirstOrDefaultAsync(x => x.Name == AppRole.ADMINISTRATOR_TYPE, cancellationToken);
                    if (adminRole == null)
                    {
                        adminRole = new AppRole()
                        {
                            Name = AppRole.ADMINISTRATOR_TYPE,
                            NormalizedName = AppRole.ADMINISTRATOR_TYPE.Normalize()
                        };
                        context.Set<AppRole>().Add(adminRole);
                    }

                    var operatorRole = await context.Set<AppRole>().FirstOrDefaultAsync(x => x.Name == AppRole.OPERATOR_TYPE, cancellationToken);
                    if (operatorRole == null)
                    {
                        context.Set<AppRole>().Add(new AppRole()
                        {
                            Name = AppRole.OPERATOR_TYPE,
                            NormalizedName = AppRole.OPERATOR_TYPE.Normalize()
                        });
                    }

                    var observerRole = await context.Set<AppRole>().FirstOrDefaultAsync(x => x.Name == AppRole.OBSERVER_TYPE, cancellationToken);
                    if (observerRole == null)
                    {
                        context.Set<AppRole>().Add(new AppRole()
                        {
                            Name = AppRole.OBSERVER_TYPE,
                            NormalizedName = AppRole.OBSERVER_TYPE.Normalize()
                        });
                    }

                    var adminUser = await context.Set<AppUser>().FirstOrDefaultAsync(x => x.UserName == AppUser.ADMINISTRATOR_USER_NAME, cancellationToken);
                    var hasAdmin = adminUser != null;
                    if (!hasAdmin)
                    {
                        adminUser = new AppUser()
                        {
                            UserName = AppUser.ADMINISTRATOR_USER_NAME,
                            NormalizedUserName = AppUser.ADMINISTRATOR_USER_NAME.Normalize(),
                            LockoutEnabled = true
                        };

                        var passwordHasher = new PasswordHasher<AppUser>();
                        adminUser.PasswordHash = passwordHasher.HashPassword(adminUser, AppUser.ADMINISTRATOR_PASSWORD);

                        var entry = context.Set<AppUser>().Add(adminUser);
                    }

                    await context.SaveChangesAsync();

                    if (!hasAdmin)
                    {
                        context.Set<IdentityUserRole<string>>().Add(new IdentityUserRole<string>()
                        {
                            UserId = adminUser.Id,
                            RoleId = adminRole.Id
                        });
                    }

                    await context.SaveChangesAsync();
                });

            base.OnConfiguring(optionsBuilder);
        }
    }
}
