using Backend.Contracts;
using Backend.Common;
using Backend.Data;
using Backend.Domain;
using Backend.Services;
using Microsoft.EntityFrameworkCore;

namespace Backend.Endpoints;

public static partial class AdminSeasonManagementEndpoints
{
    private static async Task<IResult> CreateCategory(
        HttpContext context,
        int seasonId,
        UpsertCategoryRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var validationError = ValidateCategoryRequest(request);
        if (validationError is not null)
        {
            return validationError;
        }

        var season = await db.Seasons.FirstOrDefaultAsync(item => item.Id == seasonId);
        if (season is null)
        {
            return Results.NotFound();
        }

        var normalizedSlug = request.Slug.Trim();
        if (await db.Categories.AnyAsync(item =>
                item.SeasonId == seasonId
                && item.Slug.ToLower() == normalizedSlug.ToLower()))
        {
            return Results.BadRequest(new { message = "A category with this slug already exists in the selected season." });
        }

        var category = new Category
        {
            SeasonId = seasonId,
            GroupName = request.GroupName.Trim(),
            Name = request.Name.Trim(),
            Slug = normalizedSlug,
            Description = request.Description.Trim(),
            SortOrder = request.SortOrder,
            MaxNomineesPerUser = request.MaxNomineesPerUser,
            ViewerRangeMin = request.ViewerRangeMin,
            ViewerRangeMax = request.ViewerRangeMax,
        };

        db.Categories.Add(category);
        adminAuditService.AddEntry(
            session.TwitchUserId,
            "category.create",
            "category",
            request.Slug.Trim(),
            $"Kategorie {request.Name.Trim()} wurde angelegt.",
            new { seasonId, request.GroupName, request.SortOrder },
            RequestMetadataReader.Read(context));

        await db.SaveChangesAsync(context.RequestAborted);
        return Results.Ok(new { saved = true, categoryId = category.Id });
    }

    private static async Task<IResult> UpdateCategory(
        HttpContext context,
        int categoryId,
        UpsertCategoryRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var validationError = ValidateCategoryRequest(request);
        if (validationError is not null)
        {
            return validationError;
        }

        var category = await db.Categories.FirstOrDefaultAsync(item => item.Id == categoryId);
        if (category is null)
        {
            return Results.NotFound();
        }

        var normalizedSlug = request.Slug.Trim();
        if (await db.Categories.AnyAsync(item =>
                item.SeasonId == category.SeasonId
                && item.Id != categoryId
                && item.Slug.ToLower() == normalizedSlug.ToLower()))
        {
            return Results.BadRequest(new { message = "A category with this slug already exists in the selected season." });
        }

        category.GroupName = request.GroupName.Trim();
        category.Name = request.Name.Trim();
        category.Slug = normalizedSlug;
        category.Description = request.Description.Trim();
        category.SortOrder = request.SortOrder;
        category.MaxNomineesPerUser = request.MaxNomineesPerUser;
        category.ViewerRangeMin = request.ViewerRangeMin;
        category.ViewerRangeMax = request.ViewerRangeMax;

        adminAuditService.AddEntry(
            session.TwitchUserId,
            "category.update",
            "category",
            category.Id.ToString(),
            $"Kategorie {request.Name.Trim()} wurde aktualisiert.",
            new { request.GroupName, request.SortOrder, request.MaxNomineesPerUser },
            RequestMetadataReader.Read(context));

        await db.SaveChangesAsync(context.RequestAborted);
        return Results.Ok(new { saved = true, categoryId = category.Id });
    }

    private static async Task<IResult> DeleteCategory(
        HttpContext context,
        int categoryId,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var category = await db.Categories.FirstOrDefaultAsync(item => item.Id == categoryId);
        if (category is null)
        {
            return Results.NotFound();
        }

        var candidates = await db.Candidates.Where(item => item.CategoryId == categoryId).ToArrayAsync();
        if (candidates.Length > 0)
        {
            db.Candidates.RemoveRange(candidates);
        }

        db.Categories.Remove(category);
        adminAuditService.AddEntry(
            session.TwitchUserId,
            "category.delete",
            "category",
            category.Id.ToString(),
            $"Kategorie {category.Name} wurde gelöscht.",
            new { removedCandidates = candidates.Length },
            RequestMetadataReader.Read(context));

        await db.SaveChangesAsync(context.RequestAborted);
        return Results.Ok(new { deleted = true, categoryId });
    }
}
