using Microsoft.EntityFrameworkCore;

namespace Netina.Repository.Services;


public class DbInitializerService : IDbInitializerService
{
    private readonly IOptionsSnapshot<SiteSettings> _adminUserSeedOptions;
    private readonly ApplicationContext _context;
    private readonly ILogger<DbInitializerService> _logger;
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;

    public DbInitializerService(
        ApplicationContext context,
        RoleManager<ApplicationRole> roleManager,
        UserManager<ApplicationUser> userManager,
        IOptionsSnapshot<SiteSettings> adminUserSeedOptions,
        ILogger<DbInitializerService> logger,
        IRepositoryWrapper repositoryWrapper)
    {
        _context = context;
        _roleManager = roleManager;
        _userManager = userManager;
        _adminUserSeedOptions = adminUserSeedOptions;
        _logger = logger;
        _repositoryWrapper = repositoryWrapper;
    }

    public void Initialize()
    {
        try
        {
            _context.Database.Migrate();
            _logger.LogInformation("Migration SUCCESS !!!!");
        }
        catch (Exception e)
        {
            _logger.LogError(e, e.Message);
        }
    }

    public async Task SeedDate(bool force = false)
    {
        try
        {
            await SeedRoles();
            var seedAdmin = _adminUserSeedOptions.Value.UserSetting;
            var manager = _adminUserSeedOptions.Value.Manager;
            var user = await _userManager.FindByNameAsync(seedAdmin.Username);
            if (user == null)
            {
                var adminUser = new ApplicationUser
                {
                    UserName = seedAdmin.Username,
                    Email = seedAdmin.Email,
                    EmailConfirmed = true,
                    LockoutEnabled = true,
                    FirstName = seedAdmin.FirstName,
                    LastName = seedAdmin.LastName,
                    Gender = Gender.Male,
                    PhoneNumberConfirmed = true,
                    PhoneNumber = seedAdmin.Phone,
                    BirthDate = DateTime.Now.AddYears(-23)
                };
                var adminUserResult = await _userManager.CreateAsync(adminUser, seedAdmin.Password);
                _repositoryWrapper.SetRepository<Manager>()
                    .Add(new Manager
                    {
                        UserId = adminUser.Id
                    });
                await _repositoryWrapper.SaveChangesAsync(default);
                if (adminUserResult.Succeeded) await _userManager.AddToRoleAsync(adminUser, seedAdmin.RoleName);
            }

            var mahanUser = await _userManager.FindByNameAsync(manager.Username);
            if (mahanUser == null)
            {
                mahanUser = new ApplicationUser
                {
                    UserName = manager.Username,
                    Email = manager.Email,
                    EmailConfirmed = true,
                    LockoutEnabled = true,
                    FirstName = manager.FirstName,
                    LastName = manager.LastName,
                    Gender = Gender.Male,
                    PhoneNumberConfirmed = true,
                    PhoneNumber = manager.Phone,
                    BirthDate = DateTime.Now.AddYears(-23)
                };
                var adminUserResult = await _userManager.CreateAsync(mahanUser, seedAdmin.Password);
                _repositoryWrapper.SetRepository<Manager>()
                    .Add(new Manager
                    {
                        UserId = mahanUser.Id
                    });
                await _repositoryWrapper.SaveChangesAsync(default);
                if (adminUserResult.Succeeded) await _userManager.AddToRoleAsync(mahanUser, "Manager");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }

    public async Task SeedRoles()
    {
        var seedAdmin = _adminUserSeedOptions.Value.UserSetting;
        var rootRole = await _roleManager.FindByNameAsync(seedAdmin.RoleName);
        if (rootRole == null)
        {
            rootRole = new ApplicationRole
            {
                Name = seedAdmin.RoleName,
                EnglishName = seedAdmin.RoleName,
                Description = "root admin role"
            };
            var adminRoleResult = await _roleManager.CreateAsync(rootRole);
            foreach (var claim in ApplicationClaims.AllClaims)
                await _roleManager.AddClaimAsync(rootRole, claim);
        }
        else
        {
            foreach (var claim in ApplicationClaims.AllClaims)
            {
                var claims = await _roleManager.GetClaimsAsync(rootRole);
                if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
                    await _roleManager.AddClaimAsync(rootRole, claim);
            }
        }

        var managerRole = await _roleManager.FindByNameAsync("Manager");
        if (managerRole == null)
        {
            managerRole = new ApplicationRole
            {
                Name = "Manager",
                EnglishName = "Manager",
                PersianName = "مدیریتـــ",
                Description = "admin role"
            };
            var adminRoleResult = await _roleManager.CreateAsync(managerRole);
            foreach (var claim in ApplicationClaims.AllClaims)
                await _roleManager.AddClaimAsync(managerRole, claim);
        }
        else
        {
            foreach (var claim in ApplicationClaims.AllClaims)
            {
                var claims = await _roleManager.GetClaimsAsync(managerRole);
                if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
                    await _roleManager.AddClaimAsync(managerRole, claim);
            }
        }

        var customerRole = await _roleManager.FindByNameAsync("Customer");
        if (customerRole == null)
        {
            customerRole = new ApplicationRole
            {
                Name = "Customer",
                PersianName = "مشتری",
                EnglishName = "Customer",

            };
            var customerRoleResult = await _roleManager.CreateAsync(customerRole);
            foreach (var claim in ApplicationClaims.CustomerClaims)
                await _roleManager.AddClaimAsync(customerRole, claim);
        }
        else
        {
            foreach (var claim in ApplicationClaims.CustomerClaims)
            {
                var claims = await _roleManager.GetClaimsAsync(customerRole);
                if (claims.FirstOrDefault(c => c.Value == claim.Value) == null)
                    await _roleManager.AddClaimAsync(customerRole, claim);
            }
        }
    }

    public async Task Refactor()
    {
        //var noSlugProducts = await _repositoryWrapper.SetRepository<Product>()
        //    .TableNoTracking
        //    .Where(p => p.Slug == string.Empty)
        //    .ToListAsync();

        //if (noSlugProducts.Count > 0)
        //{
        //    noSlugProducts.ForEach(p =>
        //    {
        //        var slug = StringExtensions.GetSlug(p.PersianName);
        //        p.Slug = slug;
        //    });
        //    _repositoryWrapper.SetRepository<Product>()
        //        .UpdateRange(noSlugProducts);
        //    await _repositoryWrapper.SaveChangesAsync();
        //}

        //var noSlugProductCategories = await _repositoryWrapper.SetRepository<ProductCategory>()
        //    .TableNoTracking
        //    .Where(pc => pc.Slug == string.Empty)
        //    .ToListAsync();
        //if (noSlugProductCategories.Count > 0)
        //{
        //    noSlugProductCategories.ForEach(p =>
        //    {
        //        var slug = StringExtensions.GetSlug(p.Name);
        //        p.Slug = slug;
        //    });
        //    _repositoryWrapper.SetRepository<ProductCategory>()
        //        .UpdateRange(noSlugProductCategories);
        //    await _repositoryWrapper.SaveChangesAsync();
        //}

        //var notSlugBrands = await _repositoryWrapper.SetRepository<Brand>()
        //    .TableNoTracking
        //    .Where(pc => pc.Slug == string.Empty)
        //    .ToListAsync();
        //if (notSlugBrands.Count > 0)
        //{
        //    notSlugBrands.ForEach(p =>
        //    {
        //        var slug = StringExtensions.GetSlug(p.PersianName);
        //        p.Slug = slug;
        //    });
        //    _repositoryWrapper.SetRepository<Brand>()
        //        .UpdateRange(notSlugBrands);
        //    await _repositoryWrapper.SaveChangesAsync();
        //}



        //var noSlugBlogs = await _repositoryWrapper.SetRepository<Blog>()
        //    .TableNoTracking
        //    .Where(pc => pc.Slug == string.Empty)
        //    .ToListAsync();
        //if (noSlugBlogs.Count > 0)
        //{
        //    noSlugBlogs.ForEach(p =>
        //    {
        //        var slug = StringExtensions.GetSlug(p.Title);
        //        p.Slug = slug;
        //    });
        //    _repositoryWrapper.SetRepository<Blog>()
        //        .UpdateRange(noSlugBlogs);
        //    await _repositoryWrapper.SaveChangesAsync();
        //}
        //var noSlugBogCategories = await _repositoryWrapper.SetRepository<BlogCategory>()
        //    .TableNoTracking
        //    .Where(pc => pc.Slug == string.Empty)
        //    .ToListAsync();
        //if (noSlugBogCategories.Count > 0)
        //{
        //    noSlugBogCategories.ForEach(p =>
        //    {
        //        var slug = StringExtensions.GetSlug(p.Name);
        //        p.Slug = slug;
        //    });
        //    _repositoryWrapper.SetRepository<BlogCategory>()
        //        .UpdateRange(noSlugBogCategories);
        //    await _repositoryWrapper.SaveChangesAsync();
        //}
    }
}