using System.Security.Claims;
using GameList.Domain;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;

namespace GameList.Infrastructure;

public static class PlayerIdentityExtensions
{
    public const string PlayerCookieName = "player";
    public const string AdminClaim = "is_admin";
    public const string AdminPolicy = "AdminOnly";

    public static async Task SignInPlayerAsync(HttpContext ctx, Player player)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, player.Id.ToString()),
            new Claim(ClaimTypes.Name, player.Username),
            new Claim(AdminClaim, player.IsAdmin ? "true" : "false")
        };

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);

        await ctx.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
    }

    public static Task SignOutPlayerAsync(HttpContext ctx) => ctx.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    public static IApplicationBuilder UseGlobalExceptionLogging(this IApplicationBuilder app)
    {
        app.UseExceptionHandler(handler =>
        {
            handler.Run(async context =>
            {
                var feature = context.Features.Get<IExceptionHandlerFeature>();
                var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger("GlobalException");
                if (feature?.Error != null)
                {
                    logger.LogError(feature.Error, "Unhandled exception");
                }

                context.Response.StatusCode = StatusCodes.Status500InternalServerError;
                context.Response.ContentType = "application/json";
                var problem = new ProblemDetails
                {
                    Status = StatusCodes.Status500InternalServerError,
                    Title = "Internal Server Error",
                    Detail = "Unexpected server error"
                };
                problem.Extensions["error"] = "Unexpected server error";
                await context.Response.WriteAsJsonAsync(problem);
            });
        });
        return app;
    }

    public static IEndpointRouteBuilder MapHealthChecks(this IEndpointRouteBuilder endpoints)
    {
        endpoints.MapGet("/health", () => Results.Ok(new { status = "ok" }));
        return endpoints;
    }
}
