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> CreateCandidate(
        HttpContext context,
        int seasonId,
        UpsertCandidateRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var validationError = ValidateCandidateRequest(request);
        if (validationError is not null)
        {
            return validationError;
        }

        var category = await db.Categories.FirstOrDefaultAsync(item => item.Id == request.CategoryId && item.SeasonId == seasonId);
        if (category is null)
        {
            return Results.BadRequest(new { message = "The selected category does not exist in this season." });
        }

        var normalizedDisplayName = request.DisplayName.Trim();
        var normalizedChannelSlug = request.ChannelSlug.Trim();
        if (await db.Candidates.AnyAsync(item =>
                item.SeasonId == seasonId
                && item.CategoryId == request.CategoryId
                && (item.DisplayName.ToLower() == normalizedDisplayName.ToLower()
                    || item.ChannelSlug.ToLower() == normalizedChannelSlug.ToLower())))
        {
            return Results.BadRequest(new { message = "A candidate with the same display name or channel slug already exists in this category." });
        }

        var candidate = new Candidate
        {
            SeasonId = seasonId,
            CategoryId = request.CategoryId,
            DisplayName = normalizedDisplayName,
            ChannelSlug = normalizedChannelSlug,
            Platform = request.Platform.Trim(),
        };

        db.Candidates.Add(candidate);
        adminAuditService.AddEntry(
            session.TwitchUserId,
            "candidate.create",
            "candidate",
            request.DisplayName.Trim(),
            $"Kandidat {request.DisplayName.Trim()} wurde angelegt.",
            new { seasonId, request.CategoryId, request.Platform },
            RequestMetadataReader.Read(context));

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

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

        var candidate = await db.Candidates.FirstOrDefaultAsync(item => item.Id == candidateId);
        if (candidate is null)
        {
            return Results.NotFound();
        }

        var targetCategory = await db.Categories.FirstOrDefaultAsync(item =>
            item.Id == request.CategoryId && item.SeasonId == candidate.SeasonId);
        if (targetCategory is null)
        {
            return Results.BadRequest(new { message = "The selected category does not exist in this season." });
        }

        var normalizedDisplayName = request.DisplayName.Trim();
        var normalizedChannelSlug = request.ChannelSlug.Trim();
        if (await db.Candidates.AnyAsync(item =>
                item.SeasonId == candidate.SeasonId
                && item.CategoryId == request.CategoryId
                && item.Id != candidateId
                && (item.DisplayName.ToLower() == normalizedDisplayName.ToLower()
                    || item.ChannelSlug.ToLower() == normalizedChannelSlug.ToLower())))
        {
            return Results.BadRequest(new { message = "A candidate with the same display name or channel slug already exists in this category." });
        }

        candidate.CategoryId = request.CategoryId;
        candidate.DisplayName = normalizedDisplayName;
        candidate.ChannelSlug = normalizedChannelSlug;
        candidate.Platform = request.Platform.Trim();

        adminAuditService.AddEntry(
            session.TwitchUserId,
            "candidate.update",
            "candidate",
            candidate.Id.ToString(),
            $"Kandidat {request.DisplayName.Trim()} wurde aktualisiert.",
            new { request.CategoryId, request.Platform },
            RequestMetadataReader.Read(context));

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

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

        db.Candidates.Remove(candidate);
        adminAuditService.AddEntry(
            session.TwitchUserId,
            "candidate.delete",
            "candidate",
            candidate.Id.ToString(),
            $"Kandidat {candidate.DisplayName} wurde gelöscht.",
            new { candidate.CategoryId, candidate.Platform },
            RequestMetadataReader.Read(context));

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