using Duende.IdentityServer;
using Duende.IdentityServer.Models;
using IdentityModel;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using ZeroFramework.IdentityServer.API.Constants;
using ZeroFramework.IdentityServer.API.Tenants;

namespace ZeroFramework.IdentityServer.API.IdentityStores
{
    public static class SampleDatas
    {
        public static IEnumerable<IdentityResource> Ids => new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new("userinfo", "Your user information", new []
            {
                JwtClaimTypes.Role,
                JwtRegisteredClaimNames.UniqueName,
                JwtClaimTypes.NickName,
                JwtClaimTypes.Address,
                JwtClaimTypes.Email
            })
        };

        public static IEnumerable<ApiResource> Apis => new List<ApiResource>
        {
            new("devicecenterapi", "Device Center API",new []{ JwtClaimTypes.Email })
            {
                Scopes= { "openapi", "devicecenter" }
            },
            new("identityserverapi", "Identity Server API",new []{ JwtClaimTypes.PhoneNumber,JwtClaimTypes.BirthDate})
            {
                Scopes= { "openapi", "identityserver" }
            }
        };

        public static IEnumerable<ApiScope> ApiScopes => new List<ApiScope>
        {
            new("openapi", "All open web api", new []{ JwtClaimTypes.Role, TenantClaimTypes.TenantId, TenantClaimTypes.TenantName, JwtClaimTypes.Name}),
            new("identityserver", "Identity server api", new []{ JwtClaimTypes.Role, TenantClaimTypes.TenantId, TenantClaimTypes.TenantName, JwtClaimTypes.Name}),
            new("devicecenter", "Device center api", new []{ JwtClaimTypes.Role, TenantClaimTypes.TenantId, TenantClaimTypes.TenantName, JwtClaimTypes.Name})
        };

        public static IEnumerable<Client> Clients => new List<Client>
        {
            new() {
                ClientId = "devicecenterswagger",
                ClientName = "Device Center Swagger",
                ClientSecrets = { new Secret("secret".Sha256())},
                AllowedGrantTypes = GrantTypes.Code,
                AllowAccessTokensViaBrowser = true,
                RequireClientSecret=false,
                AlwaysSendClientClaims=true,
                AlwaysIncludeUserClaimsInIdToken=true,
                RequireConsent = false,
                RedirectUris = {
                    "https://localhost:6001/swagger/oauth2-redirect.html",
                    "https://devicecenterapi.helloworldnet.com/swagger/oauth2-redirect.html"
                },
                PostLogoutRedirectUris = {
                    "https://localhost:6001/swagger",
                    "https://devicecenterapi.helloworldnet.com/swagger"
                },
                AllowOfflineAccess=true,
                RequirePkce = true,
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "devicecenter"
                },
                AllowedCorsOrigins = {
                    "https://localhost:6001",
                    "https://devicecenterapi.helloworldnet.com"
                },
                AccessTokenLifetime =3600*24
            },
            new() {
                ClientId = "identityserverswagger",
                ClientName = "Identity Server Swagger",
                ClientSecrets = { new Secret("secret".Sha256())},
                AllowedGrantTypes = GrantTypes.Code,
                AllowAccessTokensViaBrowser = true,
                RequireClientSecret=false,
                AlwaysSendClientClaims=true,
                AlwaysIncludeUserClaimsInIdToken=true,
                RequireConsent = false,
                RedirectUris = {
                    "https://localhost:5001/swagger/oauth2-redirect.html",
                    "https://identityserver.helloworldnet.com/swagger/oauth2-redirect.html"
                },
                PostLogoutRedirectUris = {
                    "https://localhost:5001/swagger",
                    "https://identityserver.helloworldnet.com/swagger"
                },
                AllowOfflineAccess=true,
                RequirePkce = true,
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "identityserver"
                },
                AllowedCorsOrigins = {
                    "https://localhost:5001",
                    "https://identityserver.helloworldnet.com"
                },
                AccessTokenLifetime = 3600*24
            },
            new() {
                ClientId = "devicecenterweb",
                ClientName = "Device Center Web",
                AllowedGrantTypes = GrantTypes.Code,
                AllowAccessTokensViaBrowser = true,
                RequireClientSecret=false,
                AlwaysSendClientClaims=true,
                AlwaysIncludeUserClaimsInIdToken=true,
                RequireConsent = false,
                RedirectUris = {
                    "http://localhost:8000/authorization/login-callback",
                    "https://cloud.helloworldnet.com/authorization/login-callback"
                },
                PostLogoutRedirectUris = {
                    "http://localhost:8000/authorization/logout-callback",
                    "https://cloud.helloworldnet.com/authorization/logout-callback"
                },
                AllowOfflineAccess=true,
                RequirePkce = true,
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "userinfo",
                    "openapi",
                    "identityserver",
                    "devicecenter"
                },
                AllowedCorsOrigins = {
                    "http://localhost:8000",
                    "https://cloud.helloworldnet.com"
                },
                AccessTokenLifetime = 3600*24
            }
        };

        public static IEnumerable<IdentityTenant> Tenants()
        {
            Random random = new(Environment.TickCount);

            var result = new List<IdentityTenant>();

            for (int i = 1; i < 3; i++)
            {
                result.Add(new IdentityTenant()
                {
                    Id = Guid.Parse($"5f6f2110-58b6-4cf9-b416-85820ba12c0{i}"),
                    Name = $"tenant{i}",
                    CreationTime = DateTime.Now.AddMinutes(-random.Next(0, 10000)),
                    NormalizedName = $"tenant{i}".ToUpper(),
                    DisplayName = $"公司租户{i}"
                });
            }

            return result;
        }

        public static IEnumerable<ApplicationRole> Roles()
        {
            var result = new List<ApplicationRole>();

            var tenants = Tenants().ToArray();

            result.Add(new ApplicationRole { Name = AuthorizeConstants.TenantOwnerRequireRole, TenantId = null, TenantRoleName = AuthorizeConstants.TenantOwnerRequireRole, DisplayName = "租户所有者" });

            for (int i = 1; i < 3; i++)
            {
                string tenantRoleName = $"role{i}";
                result.Add(new ApplicationRole { Name = tenantRoleName, TenantId = null, TenantRoleName = tenantRoleName, DisplayName = $"宿主角色{i}" });
            }

            for (int i = 0; i < tenants.Length; i++)
            {
                result.Add(new ApplicationRole
                {
                    Name = $"{AuthorizeConstants.TenantOwnerRequireRole}@{tenants[i].Name}",
                    TenantId = tenants[i].Id,
                    TenantRoleName = AuthorizeConstants.TenantOwnerRequireRole,
                    DisplayName = $"租户所有者{i}"
                });

                for (int j = 1; j < 3; j++)
                {
                    string tenantRoleName = $"role{j}";

                    result.Add(new ApplicationRole
                    {
                        Name = $"{tenantRoleName}@{tenants[i].Name}",
                        TenantId = tenants[i].Id,
                        TenantRoleName = tenantRoleName,
                        DisplayName = $"租户角色{i}"
                    });
                }
            }

            return result;
        }

        public static Dictionary<ApplicationUser, IEnumerable<Claim>> Users()
        {
            var tenants = Tenants().ToArray();
            var roles = Roles().ToArray();

            Random random = new(Environment.TickCount);

            string stringMock() => $"{Path.GetRandomFileName().Replace(".", string.Empty)}";
            string phoneMock() => $"{random.Next(130, 190)}{random.Next(10000000, 99999999)}";
            DateTimeOffset dateMock() => DateTimeOffset.Now.AddDays(-random.Next(1, 365 * 30));

            Dictionary<ApplicationUser, IEnumerable<Claim>> result = [];

            var currentHostRoles = roles.Where(r => r.TenantId == null).ToArray();
            List<Claim> claims = currentHostRoles.Select(r => new Claim(JwtClaimTypes.Role, r.Name!, ClaimValueTypes.String)).ToList();
            claims.Add(new Claim(JwtClaimTypes.BirthDate, dateMock().ToString("yyyy-MM-dd"), ClaimValueTypes.Date));
            var user = new ApplicationUser
            {
                UserName = "admin",
                PasswordHash = "guest",
                PhoneNumber = phoneMock(),
                Email = "admin@helloworldnet.com",
                TenantId = null,
                TenantUserName = "admin",
                DisplayName = "超级管理员"
            };
            result[user] = claims;

            for (int i = 1; i < 3; i++)
            {
                IdentityTenant tenant = tenants[i - 1];
                var currentTenantRoles = roles.Where(r => r.TenantId == tenant.Id).ToArray();
                if (i == 2)
                {
                    currentTenantRoles = currentTenantRoles.Where(r => r.TenantRoleName != AuthorizeConstants.TenantOwnerRequireRole).ToArray();
                }
                claims = currentTenantRoles.Select(r => new Claim(JwtClaimTypes.Role, r.Name!, ClaimValueTypes.String)).ToList();
                claims.Add(new Claim(JwtClaimTypes.BirthDate, dateMock().ToString("yyyy-MM-dd"), ClaimValueTypes.Date));
                user = new ApplicationUser
                {
                    UserName = $"guest{i}@{tenant.Name}",
                    PasswordHash = $"guest",
                    PhoneNumber = phoneMock(),
                    Email = $"guest{i}@helloworldnet.com",
                    TenantId = tenant.Id,
                    TenantUserName = $"guest{i}",
                    DisplayName = $"来宾访客{i}"
                };
                result[user] = claims;
            }

            for (int i = 1; i < 100; i++)
            {
                var tenant = tenants[random.Next(0, tenants.Length)];

                var currentUserRoles = roles.Where(r => r.TenantId == tenant.Id).ToArray();

                string tenantUserName = $"user{i.ToString().PadLeft(2, '0')}";

                claims =
                [
                    new(JwtClaimTypes.BirthDate, dateMock().ToString("yyyy-MM-dd"), ClaimValueTypes.Date),
                    new(JwtClaimTypes.Role, currentUserRoles[random.Next(0, currentUserRoles.Length)].Name!, ClaimValueTypes.String),
                ];

                user = new ApplicationUser
                {
                    UserName = $"{tenantUserName}@{tenant.Name}",
                    PasswordHash = tenantUserName,
                    PhoneNumber = phoneMock(),
                    Email = $"{stringMock()}@helloworldnet.com",
                    TenantId = tenant.Id,
                    TenantUserName = tenantUserName,
                    DisplayName = $"普通用户{i.ToString().PadLeft(2, '0')}"
                };
                result[user] = claims;
            }

            return result;
        }
    }
}