using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using Auth.Entities;
using Microsoft.IdentityModel.Tokens;

namespace Auth.Services {
    public class AuthJWT {

        public static Dictionary<string, JWTMemCache> LoginSessions = new Dictionary<string, JWTMemCache>();
        public static RsaSecurityKey RsaPublicKey = LoadRSAKey("/certs/public_key.pem");
        public static RsaSecurityKey RsaPrivateKey = LoadRSAKey("/certs/private_key.pem");

        public static string TokenAudience = "mistox-llc-auth-token";
        public static string TokenIssuer = "https://auth.mistox.com";
        public static string TokenName = "mistox_session";
        public static TokenValidationParameters TokenParameters = new TokenValidationParameters {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = TokenIssuer,
            ValidAudience = TokenAudience,
            IssuerSigningKey = RsaPublicKey,
            ClockSkew = TimeSpan.FromMinutes(1)
        };

        public static string GenereateJWTToken(Account account, bool StayLoggedIn) {
            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
            SecurityTokenDescriptor tokenDiscriptor = new SecurityTokenDescriptor {
                Subject = new ClaimsIdentity([
                    new Claim(ClaimTypes.NameIdentifier, account.ID.ToString()),
                    new Claim(ClaimTypes.Name, account.UserName),
                    new Claim(ClaimTypes.Email, account.Email),
                    new Claim(ClaimTypes.Role, account.Role),
                    new Claim(ClaimTypes.UserData, account.DataServer),
                    new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()),
                ]),
                Expires = DateTime.UtcNow.AddDays(7),
                IssuedAt = DateTime.UtcNow,
                SigningCredentials = new SigningCredentials(RsaPrivateKey, SecurityAlgorithms.RsaSha256),
                Audience = TokenAudience,
                Issuer = TokenIssuer
            };

            var token = tokenHandler.CreateToken(tokenDiscriptor);
            return tokenHandler.WriteToken(token);
        }

        public static string RenewJWTToken(ClaimsPrincipal principal) {
            return GenereateJWTToken(new Account {
                ID = Convert.ToInt32(principal.FindFirst(ClaimTypes.NameIdentifier)!.Value),
                UserName = principal.FindFirst(ClaimTypes.Name)!.Value,
                Email = principal.FindFirst(ClaimTypes.Email)!.Value,
                Role = principal.FindFirst(ClaimTypes.Role)!.Value,
                DataServer = principal.FindFirst(ClaimTypes.UserData)!.Value
            }, Convert.ToBoolean(principal.FindFirst(ClaimTypes.IsPersistent)!.Value));
        }

        public static RsaSecurityKey LoadRSAKey(string KeyPath) {
            if (!File.Exists(KeyPath)) {
                Console.WriteLine("Unable to load certificate from path: " + KeyPath);
                Console.WriteLine("---- Shutting down ----");
                Environment.Exit(100);
            }
            string KeyText = File.ReadAllText(KeyPath);
            RSA rsa = RSA.Create();
            rsa.ImportFromPem(KeyText.ToCharArray());
            return new RsaSecurityKey(rsa);
        }

    }
}