using System.Reflection;
using Fengling.AuthService.Configuration;
using Fengling.AuthService.Data;
using Fengling.AuthService.Models;
using Fengling.Platform.Infrastructure;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi;
using NetCorePal.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Serilog;
using SeedData = Fengling.AuthService.Data.SeedData;

var builder = WebApplication.CreateBuilder(args);

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .Enrich.FromLogContext()
    .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

builder.Host.UseSerilog();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseNpgsql(connectionString);
    options.UseOpenIddict();
});


builder.Services.AddDbContext<PlatformDbContext>(options =>
{
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));
    options.UseOpenIddict();
});


builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    options.Cookie.Name = "Fengling.Auth";
    options.Cookie.SecurePolicy = CookieSecurePolicy.None;
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.ExpireTimeSpan = TimeSpan.FromDays(7);
});

builder.Services.AddOpenIddictConfiguration(builder.Configuration);

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource =>
        resource.AddService("Fengling.AuthService"))
    .WithTracing(tracing =>
        tracing.AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddSource("OpenIddict.Server.AspNetCore")
            .AddOtlpExporter());

builder.Services.AddControllersWithViews();

builder.Services.AddHealthChecks()
    .AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!);


builder.Services.AddRepositories(typeof(ApplicationDbContext).Assembly, typeof(PlatformDbContext).Assembly);
builder.Services.AddMediatR(x => x.RegisterServicesFromAssemblies(typeof(PlatformDbContext).Assembly
        , Assembly.GetExecutingAssembly())
    .AddCommandLockBehavior()
    .AddKnownExceptionValidationBehavior()
    .AddUnitOfWorkBehaviors()
);
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "Fengling Auth Service",
        Version = "v1",
        Description = "Authentication and authorization service using OpenIddict"
    });

    options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.OAuth2,
        Flows = new OpenApiOAuthFlows
        {
            Password = new OpenApiOAuthFlow
            {
                TokenUrl = new Uri("/connect/token", UriKind.Relative)
            }
        }
    });
});

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    await SeedData.Initialize(scope.ServiceProvider);
}

app.UseCors(x =>
{
    x.SetIsOriginAllowed(origin => true)
        .AllowAnyHeader()
        .AllowAnyMethod()
        .AllowCredentials()
        .Build();
});
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

var isTesting = builder.Configuration.GetValue<bool>("Testing", false);
if (!isTesting)
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "Fengling Auth Service v1");
        options.OAuthClientId("swagger-ui");
        options.OAuthUsePkce();
    });
}

app.MapRazorPages();
app.MapControllers();
app.MapHealthChecks("/health");

app.Run();