using Auth.Services;
using Auth.Services.DatabaseService;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Disable null warnings becuse string.IsNullOrEmpty checks for NULL or Empty
#pragma warning disable CS8604

////////////////////////////////
/////// Database Service ///////
////////////////////////////////

// Address
string? _dbserver = Environment.GetEnvironmentVariable("MySQLServer");
string dbserver = !string.IsNullOrEmpty(_dbserver) ? _dbserver : "localhost";

// Database
string? _dbdatabase = Environment.GetEnvironmentVariable("MySQLDatabase");
string dbdatabase = !string.IsNullOrEmpty(_dbdatabase) ? _dbdatabase : "Auth";

// UserName
string? _dbuser = Environment.GetEnvironmentVariable("MySQLUser");
string dbUser = !string.IsNullOrEmpty(_dbuser) ? _dbuser : "root"; 

// Password
string? _dbpass = Environment.GetEnvironmentVariable("MySQLPass");
string dbPass = !string.IsNullOrEmpty(_dbpass) ? _dbpass : "oasv34$8gpv023dd";

// Create the database serivice
DatabaseService databaseService = new DatabaseService(connectionString: "server=" + dbserver + ";user=" + dbUser + ";database=" + dbdatabase + ";password=" + dbPass + ";port=3307;");
builder.Services.Add( new ServiceDescriptor( typeof( DatabaseService ), databaseService ) );

////////////////////////////////
////////// Auth Service ////////
////////////////////////////////

// Address
string? _jwtSecret = Environment.GetEnvironmentVariable("JWTsecret");
string JWTsecret = !string.IsNullOrEmpty(_jwtSecret) ? _jwtSecret : "v0Ftluhdh7Nht8^2b5eaiC^IS^VS1ku0VBs3j*B2";
AuthJWT.TokenSecretKey = JWTsecret;

////////////////////////////////
///////// Email Service ////////
////////////////////////////////

// Address
string? _eServer = Environment.GetEnvironmentVariable("EmailServer");
string EmailServer = !string.IsNullOrEmpty(_eServer) ? _eServer : "mail.mistox.com";

// Port
string? _ePort = Environment.GetEnvironmentVariable("EmailPort");
int EmailPort = !string.IsNullOrEmpty(_ePort) ? Convert.ToInt32(_ePort) : 587;

// User
string? _eAddress = Environment.GetEnvironmentVariable("EmailAddress");
string EmailAddress = !string.IsNullOrEmpty(_eAddress) ? _eAddress : "no-reply@mistox.com";

// Password
string? _ePassword = Environment.GetEnvironmentVariable("EmailPassword");
string EmailPassword = !string.IsNullOrEmpty(_ePassword) ? _ePassword : "";

// Create the email service
EmailService Emailservice = new EmailService( EmailServer, EmailPort, EmailAddress, EmailPassword );
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));

// Authentication Service
builder.Services.AddAuthentication(options => {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => {
    options.TokenValidationParameters = new TokenValidationParameters {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = AuthJWT.TokenIssuer,
        ValidAudience = AuthJWT.TokenAudience,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AuthJWT.TokenSecretKey)),
        ClockSkew = TimeSpan.FromMinutes(1)
    };
    options.Events = new JwtBearerEvents {
        OnMessageReceived = context => {
            context.Token = context.Request.Cookies[AuthJWT.TokenName];
            return Task.CompletedTask;
        },
        OnTokenValidated = context => {
            var jwtToken = context.SecurityToken as JwtSecurityToken;
            if (jwtToken != null) {
                var exp = jwtToken.ValidTo;
                var now = DateTime.UtcNow;
                if ((exp - now) < TimeSpan.FromDays(3)) {
                    int accountID = Convert.ToInt32(context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value);
                    bool isPersistent = bool.Parse(context.Principal?.FindFirst(ClaimTypes.IsPersistent)?.Value);
                    var newJWT = AuthJWT.GenereateJWTToken(accountID, isPersistent);
                    AuthJWT.SignIn(context.HttpContext.Response, isPersistent, newJWT);
                }
            }
            return Task.CompletedTask;
        }
    };
});

builder.Services.AddCors(o => o.AddDefaultPolicy(builder => {
    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();     // No CORS
}));

// Pages Service
builder.Services.AddControllers();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if( !app.Environment.IsDevelopment() ) {
    app.UseHsts();
}

app.UseDefaultFiles();
app.UseStaticFiles();

app.UseCors();

app.UseRouting();

app.UseAuthentication();
app.MapControllers();

app.MapFallbackToFile("index.html");

app.Run();
