using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;

namespace Fengling.Platform.Infrastructure;

public static class SeedData
{
    public static async Task InitializeAsync(this IServiceScope scope)
    {
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<ApplicationRole>>();

        var context = scope.ServiceProvider.GetRequiredService<PlatformDbContext>();
        await context.Database.EnsureCreatedAsync();

        var adminTenant = context.Tenants
            .FirstOrDefault(t => t.TenantCode == "Administrator");
        if (adminTenant == null)
        {
            adminTenant = new Tenant
            {
                TenantCode = "Administrator",
                Name = "超级系统",
                ContactName = "",
                ContactEmail = "",
                Status = TenantStatus.Active,
                CreatedAt = DateTime.UtcNow
            };
            await context.Tenants.AddAsync(adminTenant);
        }

        


        var role = await roleManager.Roles
            .OfType<ApplicationRole>()
            .AsQueryable()
            .FirstOrDefaultAsync(x => x.Name == "admin" && x.TenantId == null);

        if (role == null)
        {
            role = new ApplicationRole()
            {
                CreatedTime = DateTimeOffset.UtcNow,
                TenantId = null,
                Name = "admin", Description = "系统管理员",
                DisplayName = "系统管理员",
                IsSystem = true,
            };
            await roleManager.CreateAsync(role);
        }

        var user = await userManager.FindByNameAsync("admin");
        if (user == null)
        {
            user = new ApplicationUser()
            {
                UserName = "admin",
                RealName = "系统超级管理员",
                Email = "samsu9194@163.com",
                TenantInfo = new TenantInfo(adminTenant),
                PhoneNumber = "15921072307",
                SecurityStamp =  Guid.NewGuid().ToString(),
            };
            await userManager.CreateAsync(user, "Admin@123");
            await userManager.AddToRoleAsync(user, "admin");
        }


        await context.SaveChangesAsync();

        await InitializeOpenIddictAsync(scope.ServiceProvider);

    }

    private static async Task InitializeOpenIddictAsync(IServiceProvider serviceProvider)
    {
        var applicationManager = serviceProvider.GetRequiredService<IOpenIddictApplicationManager>();
        var scopeManager = serviceProvider.GetRequiredService<IOpenIddictScopeManager>();

        await RegisterCustomScopesAsync(scopeManager);
        await RegisterVbenConsoleClientAsync(applicationManager);
        await RegisterSwaggerClientAsync(applicationManager);
        await RegisterApiClientAsync(applicationManager);
    }

    private static async Task RegisterCustomScopesAsync(IOpenIddictScopeManager scopeManager)
    {
        var fenglingApiScope = await scopeManager.FindByNameAsync("fengling_api");
        if (fenglingApiScope == null)
        {
            await scopeManager.CreateAsync(new OpenIddictScopeDescriptor
            {
                Name = "fengling_api",
                DisplayName = "Fengling API Access",
                Description = "Allow access to Fengling API resources"
            });
        }

        var authServerAdminScope = await scopeManager.FindByNameAsync("auth_server_admin");
        if (authServerAdminScope == null)
        {
            await scopeManager.CreateAsync(new OpenIddictScopeDescriptor
            {
                Name = "auth_server_admin",
                DisplayName = "Auth Server Admin",
                Description = "Allow access to auth server admin APIs"
            });
        }
    }

    private static async Task RegisterVbenConsoleClientAsync(IOpenIddictApplicationManager applicationManager)
    {
        var existingClient = await applicationManager.FindByClientIdAsync("fengling-console");
        if (existingClient != null)
        {
            return;
        }

        await applicationManager.CreateAsync(new OpenIddictApplicationDescriptor
        {
            ClientId = "fengling-console",
            DisplayName = "Fengling Console (Vben Admin)",
            ApplicationType = OpenIddictConstants.ApplicationTypes.Web,
            ClientType = OpenIddictConstants.ClientTypes.Public,
            RedirectUris =
            {
                new Uri("http://localhost:5777/auth/callback"),
                new Uri("http://localhost:5777")
            },
            PostLogoutRedirectUris =
            {
                new Uri("http://localhost:5777")
            },
            Permissions =
            {
                OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
                "hybrid",
                OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
                OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,

                OpenIddictConstants.Permissions.Endpoints.Authorization,
                OpenIddictConstants.Permissions.Endpoints.Token,
                "userinfo",
                OpenIddictConstants.Permissions.Endpoints.EndSession,

                "client_secret",

                OpenIddictConstants.Permissions.Scopes.Email,
                OpenIddictConstants.Permissions.Scopes.Profile,
                "openid",
                "offline_access",
                OpenIddictConstants.Permissions.Scopes.Roles,
                OpenIddictConstants.Permissions.ResponseTypes.Code,
                OpenIddictConstants.Permissions.ResponseTypes.CodeIdTokenToken,
                OpenIddictConstants.Permissions.Prefixes.Scope + "api",
            },
            Requirements =
            {
                OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange
            }
        });
    }

    private static async Task RegisterSwaggerClientAsync(IOpenIddictApplicationManager applicationManager)
    {
        var existingClient = await applicationManager.FindByClientIdAsync("swagger-ui");
        if (existingClient != null)
        {
            return;
        }

        await applicationManager.CreateAsync(new OpenIddictApplicationDescriptor
        {
            ClientId = "swagger-ui",
            DisplayName = "Swagger UI",
            RedirectUris =
            {
                new Uri("http://localhost:5231/swagger/oauth2-redirect.html"),
                new Uri("http://localhost:5511/swagger/oauth2-redirect.html"),
                new Uri("http://localhost:5132/swagger/oauth2-redirect.html"),
            },
            Permissions =
            {
                OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
                OpenIddictConstants.Permissions.Endpoints.Authorization,
                OpenIddictConstants.Permissions.Endpoints.Token,
                "client_secret",
                "openid"
            }
        });
    }

    private static async Task RegisterApiClientAsync(IOpenIddictApplicationManager applicationManager)
    {
        var existingClient = await applicationManager.FindByClientIdAsync("fengling-api");
        if (existingClient != null)
        {
            return;
        }

        await applicationManager.CreateAsync(new OpenIddictApplicationDescriptor
        {
            ClientId = "fengling-api",
            ClientSecret = "fengling-api-secret",
            DisplayName = "Fengling API (Resource Server)",
            ApplicationType = OpenIddictConstants.ApplicationTypes.Web,
            ClientType = OpenIddictConstants.ClientTypes.Confidential,
            Permissions =
            {
                OpenIddictConstants.Permissions.Endpoints.Introspection
            }
        });
    }
}