using System.Net;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using TvNoms.Server.ApiService.Shared;
using TvNoms.Server.Data;
using TvNoms.Server.Data.Models;
using TvNoms.Server.Services.Identity;
using TvNoms.Server.Services.Infrastructure.Messaging;
using TvNoms.Server.Services.Infrastructure.Messaging.Email;
using TvNoms.Server.Services.Infrastructure.Messaging.SMS;

var builder = WebApplication.CreateBuilder(args);

// Add service defaults & Aspire components.
builder.AddServiceDefaults();

// Add services to the container.
builder.Services.AddProblemDetails();

if (builder.Environment.IsDevelopment()) {
  builder.WebHost.ConfigureKestrel(serverOptions => {
    var pemFile = builder.Configuration["Startup:PemFile"];
    var keyFile = builder.Configuration["Startup:KeyFile"];
    var port = int.Parse(builder.Configuration["Startup:Port"] ?? "5001");
    if (string.IsNullOrEmpty(pemFile) || string.IsNullOrEmpty(keyFile)) {
      throw new InvalidOperationException("Unable to find SSL certificate files.");
    }

    serverOptions.Listen(IPAddress.Any, port, listenOptions => {
      var certPem = File.ReadAllText(pemFile);
      var keyPem = File.ReadAllText(keyFile);
      var x509 = X509Certificate2.CreateFromPem(certPem, keyPem);

      listenOptions.UseHttps(x509);
    });
  });
}

builder.Services.AddDbContext<AppDbContext>(options => {
  var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
  options.UseNpgsql(connectionString,
    sqlOptions => sqlOptions.MigrationsAssembly(typeof(AppDbContext).Assembly.GetName().Name));
});
builder.Services.AddIdentity<User, Role>(options => {
    // Password settings. (Will be using fluent validation)
    options.Password.RequireDigit = false;
    options.Password.RequireLowercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = false;
    options.Password.RequiredLength = 0;
    options.Password.RequiredUniqueChars = 0;

    // Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings.
    options.User.AllowedUserNameCharacters = string.Empty;
    options.User.RequireUniqueEmail = false;

    options.SignIn.RequireConfirmedAccount = false;
    options.SignIn.RequireConfirmedEmail = false;
    options.SignIn.RequireConfirmedPhoneNumber = false;

    // Generate Short Code for Email Confirmation using Asp.Net Identity core 2.1
    // source: https://stackoverflow.com/questions/53616142/generate-short-code-for-email-confirmation-using-asp-net-identity-core-2-1
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;

    options.ClaimsIdentity.RoleClaimType = ClaimTypes.Role;
    options.ClaimsIdentity.UserNameClaimType = ClaimTypes.Name;
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier;
    options.ClaimsIdentity.EmailClaimType = ClaimTypes.Email;
    options.ClaimsIdentity.SecurityStampClaimType = ClaimTypes.SerialNumber;
  })
  .AddEntityFrameworkStores<AppDbContext>()
  .AddDefaultTokenProviders();
builder.Services.AddClientContext();
builder.Services.AddHttpContextAccessor();

builder.Services.AddAuthentication(options => {
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  })
  .AddBearer(options => { builder.Configuration.GetRequiredSection("BearerAuthOptions").Bind(options); })
  .AddGoogle(GoogleDefaults.AuthenticationScheme, options => {
    options.SignInScheme = IdentityConstants.ExternalScheme;
    builder.Configuration.GetRequiredSection("GoogleAuthOptions").Bind(options);
  });

builder.Services.AddAuthorization();
builder.Services.AddMailgunEmailSender(options => {
  builder.Configuration.GetRequiredSection("MailgunEmailOptions").Bind(options);
});
builder.Services.AddFakeSmsSender();
builder.Services.AddDocumentations();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseExceptionHandler();

app.MapGet("/ping", () => "pong");


app.MapDefaultEndpoints();
app.MapEndpoints();

app.Run();
