using Backend.Common;
using Backend.Contracts;
using Backend.Data;
using Backend.Security;
using Backend.Services;

namespace Backend.Endpoints;

public static partial class AuthEndpoints
{
    private const int MaxTwitchUserIdLength = 64;
    private const int MaxDisplayNameLength = 80;

    private static async Task<IResult> DevLogin(
        HttpContext context,
        IHostEnvironment environment,
        LoginRequest request,
        AwardsDbContext db,
        IUserSessionService userSessionService,
        IRiskFlagService riskFlagService,
        IRiskRuleService riskRuleService)
    {
        if (!environment.IsDevelopment())
        {
            return Results.NotFound();
        }

        var normalizedTwitchUserId = request.TwitchUserId?.Trim() ?? string.Empty;
        var normalizedDisplayName = request.DisplayName?.Trim() ?? string.Empty;
        var normalizedRole = AdminRoles.Normalize(request.Role);

        if (string.IsNullOrWhiteSpace(normalizedTwitchUserId) || normalizedTwitchUserId.Length > MaxTwitchUserIdLength)
        {
            return Results.BadRequest(new { message = $"Twitch user id is required and must stay below {MaxTwitchUserIdLength} characters." });
        }

        if (!normalizedTwitchUserId.All(value => char.IsLetterOrDigit(value) || value is '_' or '-'))
        {
            return Results.BadRequest(new { message = "Twitch user id contains unsupported characters." });
        }

        if (string.IsNullOrWhiteSpace(normalizedDisplayName) || normalizedDisplayName.Length > MaxDisplayNameLength)
        {
            return Results.BadRequest(new { message = $"Display name is required and must stay below {MaxDisplayNameLength} characters." });
        }

        if (!AdminRoles.IsKnownRole(request.Role))
        {
            return Results.BadRequest(new { message = "Role must be viewer, content_admin, admin or owner." });
        }

        var requestMetadata = RequestMetadataReader.Read(context);
        var session = await userSessionService.CreateDevSessionAsync(
            request with
            {
                TwitchUserId = normalizedTwitchUserId,
                DisplayName = normalizedDisplayName,
                Role = normalizedRole,
            },
            requestMetadata,
            context.RequestAborted);

        var rapidLoginRule = await riskRuleService.GetRuleAsync("rapid_login_ip", context.RequestAborted);
        var recentSessionsFromIp = await userSessionService.CountRecentSessionsFromIpAsync(
            requestMetadata.ClientIp,
            DateTimeOffset.UtcNow.AddMinutes(-rapidLoginRule.WindowMinutes),
            context.RequestAborted);

        if (rapidLoginRule.Enabled && recentSessionsFromIp >= rapidLoginRule.Threshold)
        {
            await riskFlagService.AddIfMissingAsync(
                null,
                session.TwitchUserId,
                "login",
                "rapid_login_ip",
                rapidLoginRule.Severity,
                "Mehrere neue Sessions wurden in kurzer Zeit von derselben IP erzeugt.",
                requestMetadata,
                new
                {
                    recentSessionsFromIp,
                    threshold = rapidLoginRule.Threshold,
                    windowMinutes = rapidLoginRule.WindowMinutes,
                    entityLinks = new[]
                    {
                        new
                        {
                            label = "Audit-Log öffnen",
                            entityType = "session",
                            entityId = session.TwitchUserId,
                            to = $"/admin/users-logs?query={Uri.EscapeDataString(session.TwitchUserId)}",
                        },
                    },
                },
                context.RequestAborted);
            await db.SaveChangesAsync(context.RequestAborted);
        }

        return Results.Ok(await ToAuthSessionDtoAsync(db, userSessionService, session, false, context.RequestAborted));
    }
}
