using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace TeleWave.Infrastructure.Identity;

/// <summary>Идемпотентный сидинг: системные роли + учётка администратора из env.</summary>
public sealed class DbInitializer(
    RoleManager<AppRole> roleManager,
    UserManager<AppUser> userManager,
    IOptions<AdminSeedOptions> adminSeedOptions,
    ILogger<DbInitializer> logger
)
{
    public async Task SeedAsync(CancellationToken cancellationToken = default)
    {
        await EnsureRoleAsync(RoleNames.Admin);
        await EnsureRoleAsync(RoleNames.User);
        await SeedAdminAsync();
    }

    private async Task EnsureRoleAsync(string name)
    {
        if (await roleManager.RoleExistsAsync(name))
            return;

        var role = new AppRole(name) { IsSystem = true };
        var result = await roleManager.CreateAsync(role);
        if (!result.Succeeded)
        {
            throw new InvalidOperationException(
                $"Failed to create role '{name}': {string.Join(", ", result.Errors.Select(e => e.Description))}"
            );
        }

        logger.LogInformation("Created system role {RoleName}", name);
    }

    private async Task SeedAdminAsync()
    {
        var options = adminSeedOptions.Value;
        if (
            string.IsNullOrWhiteSpace(options.Username)
            || string.IsNullOrWhiteSpace(options.Password)
        )
        {
            logger.LogWarning(
                "AdminSeed__Username/AdminSeed__Password not set — admin account not created"
            );
            return;
        }

        if (await userManager.FindByNameAsync(options.Username) is not null)
            return;

        var admin = new AppUser { UserName = options.Username, CreatedAt = DateTimeOffset.UtcNow };

        var createResult = await userManager.CreateAsync(admin, options.Password);
        if (!createResult.Succeeded)
        {
            throw new InvalidOperationException(
                $"Failed to create admin account: {string.Join(", ", createResult.Errors.Select(e => e.Description))}"
            );
        }

        await userManager.AddToRoleAsync(admin, RoleNames.Admin);
        logger.LogInformation("Created admin account {Username}", options.Username);
    }
}
