using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Mirea.Api.Endpoint.Common.Services.Security;
using Mirea.Api.Security.Common.Interfaces;
using System;
using System.Text;

namespace Mirea.Api.Endpoint.Configuration.Core.Startup;

public static class JwtConfiguration
{
    public static AuthenticationBuilder AddJwtToken(this IServiceCollection services, IConfiguration configuration)
    {
        var lifeTimeJwt = TimeSpan.FromMinutes(int.Parse(configuration["SECURITY_LIFE_TIME_JWT"]!));

        var jwtDecrypt = Encoding.UTF8.GetBytes(configuration["SECURITY_ENCRYPTION_TOKEN"] ?? string.Empty);

        if (jwtDecrypt.Length != 32)
            throw new InvalidOperationException("The secret token \"SECURITY_ENCRYPTION_TOKEN\" cannot be less than 32 characters long. " +
                                                "Now the size is equal is " + jwtDecrypt.Length);

        var jwtKey = Encoding.UTF8.GetBytes(configuration["SECURITY_SIGNING_TOKEN"] ?? string.Empty);

        if (jwtKey.Length != 64)
            throw new InvalidOperationException("The signature token \"SECURITY_SIGNING_TOKEN\" cannot be less than 64 characters. " +
                                                "Now the size is " + jwtKey.Length);

        var jwtIssuer = configuration["SECURITY_JWT_ISSUER"];
        var jwtAudience = configuration["SECURITY_JWT_AUDIENCE"];

        if (string.IsNullOrEmpty(jwtAudience) || string.IsNullOrEmpty(jwtIssuer))
            throw new InvalidOperationException("The \"SECURITY_JWT_ISSUER\" and \"SECURITY_JWT_AUDIENCE\" are not specified");

        services.AddSingleton<IAccessToken, JwtTokenService>(_ => new JwtTokenService
        {
            Audience = jwtAudience,
            Issuer = jwtIssuer,
            Lifetime = lifeTimeJwt,
            EncryptionKey = jwtDecrypt,
            SigningKey = jwtKey
        });

        return services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = jwtIssuer,

                ValidateAudience = true,
                ValidAudience = jwtAudience,

                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(jwtKey),
                TokenDecryptionKey = new SymmetricSecurityKey(jwtDecrypt)
            };
        });
    }
}