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 AdminModerationEndpoints
{
    private static async Task<IResult> ApproveNomination(
        HttpContext context,
        int nominationId,
        ApproveNominationRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var nomination = await db.Nominations
            .Include(item => item.Category)
            .FirstOrDefaultAsync(item => item.Id == nominationId);

        if (nomination is null)
        {
            return Results.NotFound();
        }

        var rawDisplayName = request.DisplayName?.Trim() ?? string.Empty;

        if (string.IsNullOrWhiteSpace(rawDisplayName))
        {
            return Results.BadRequest(new { message = "A display name is required to approve the nomination." });
        }

        var channelSlug = request.ChannelSlug?.Trim() ?? string.Empty;
        var platform = string.IsNullOrWhiteSpace(request.Platform) ? "Twitch" : request.Platform.Trim();
        var normalizedDisplayName = rawDisplayName.ToLower();
        var normalizedChannelSlug = channelSlug.ToLower();
        var normalizedPlatform = platform.ToLower();

        var existingCandidate = await db.Candidates.FirstOrDefaultAsync(item =>
            item.SeasonId == nomination.SeasonId
            && item.CategoryId == nomination.CategoryId
            && (
                item.DisplayName.ToLower() == normalizedDisplayName
                || (!string.IsNullOrWhiteSpace(normalizedChannelSlug)
                    && item.ChannelSlug.ToLower() == normalizedChannelSlug
                    && item.Platform.ToLower() == normalizedPlatform)
            ));

        var candidate = existingCandidate;
        if (candidate is null)
        {
            candidate = new Candidate
            {
                SeasonId = nomination.SeasonId,
                CategoryId = nomination.CategoryId,
                DisplayName = rawDisplayName,
                ChannelSlug = channelSlug,
                Platform = platform,
            };

            db.Candidates.Add(candidate);
            await db.SaveChangesAsync(context.RequestAborted);
        }
        else
        {
            candidate.DisplayName = rawDisplayName;

            if (!string.IsNullOrWhiteSpace(channelSlug))
            {
                candidate.ChannelSlug = channelSlug;
            }

            if (!string.IsNullOrWhiteSpace(platform))
            {
                candidate.Platform = platform;
            }
        }

        nomination.CandidateId = candidate.Id;
        nomination.Status = "approved";
        nomination.ReviewNote = string.IsNullOrWhiteSpace(request.ReviewNote) ? null : request.ReviewNote.Trim();
        nomination.ReviewedAt = DateTimeOffset.UtcNow;
        nomination.ReviewedByTwitchId = session.TwitchUserId;

        adminAuditService.AddEntry(
            session.TwitchUserId,
            "nomination.approve",
            "nomination",
            nomination.Id.ToString(),
            $"Nominierung {nomination.Id} wurde als Kandidat uebernommen.",
            new { candidateId = candidate.Id, created = existingCandidate is null, nomination.ReviewNote },
            RequestMetadataReader.Read(context));

        await db.SaveChangesAsync(context.RequestAborted);
        return Results.Ok(new { saved = true, nominationId = nomination.Id, candidateId = candidate.Id, created = existingCandidate is null });
    }

    private static async Task<IResult> RejectNomination(
        HttpContext context,
        int nominationId,
        RejectNominationRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var nomination = await db.Nominations.FirstOrDefaultAsync(item => item.Id == nominationId);
        if (nomination is null)
        {
            return Results.NotFound();
        }

        nomination.CandidateId = null;
        nomination.Status = "rejected";
        nomination.ReviewNote = string.IsNullOrWhiteSpace(request.ReviewNote) ? null : request.ReviewNote.Trim();
        nomination.ReviewedAt = DateTimeOffset.UtcNow;
        nomination.ReviewedByTwitchId = session.TwitchUserId;

        adminAuditService.AddEntry(
            session.TwitchUserId,
            "nomination.reject",
            "nomination",
            nomination.Id.ToString(),
            $"Nominierung {nomination.Id} wurde verworfen.",
            new { nomination.ReviewNote },
            RequestMetadataReader.Read(context));

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