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

namespace Backend.Endpoints;

public static partial class AdminSeasonManagementEndpoints
{
    private static async Task<IResult> GetWorkflowRules(int seasonId, AwardsDbContext db)
    {
        var season = await db.Seasons
            .AsNoTracking()
            .FirstOrDefaultAsync(item => item.Id == seasonId);
        if (season is null)
        {
            return Results.NotFound();
        }

        var settings = await db.SiteSettings
            .AsNoTracking()
            .FirstOrDefaultAsync(item => item.Id == 1);

        return Results.Ok(new AdminWorkflowRulesResponse(WorkflowRuleSettings.Read(season, settings).Select(ToWorkflowRuleDto).ToArray()));
    }

    private static async Task<IResult> UpdateWorkflowRules(
        HttpContext context,
        int seasonId,
        UpdateWorkflowRulesRequest request,
        AwardsDbContext db,
        IAdminAuditService adminAuditService)
    {
        var session = AdminEndpointConventions.CurrentSession(context);
        var season = await db.Seasons.FirstOrDefaultAsync(item => item.Id == seasonId, context.RequestAborted);
        if (season is null)
        {
            return Results.NotFound();
        }

        var settings = await db.SiteSettings
            .AsNoTracking()
            .FirstOrDefaultAsync(item => item.Id == 1, context.RequestAborted);
        var before = WorkflowRuleSettings.Read(season, settings);
        var mergedRules = WorkflowRuleSettings.Defaults
            .Select(defaultRule =>
            {
                var requestRule = request.Rules.FirstOrDefault(item => item.Key == defaultRule.Key);
                return requestRule is null
                    ? defaultRule
                    : new WorkflowRuleSetting(
                        defaultRule.Key,
                        defaultRule.Label,
                        requestRule.Enabled,
                        requestRule.Limit,
                        requestRule.Mode,
                        defaultRule.Description);
            })
            .ToArray();

        season.WorkflowRulesJson = WorkflowRuleSettings.Serialize(mergedRules);
        var after = WorkflowRuleSettings.Read(season, settings);
        var changes = after
            .Select(rule =>
            {
                var previous = before.First(item => item.Key == rule.Key);
                return new
                {
                    field = rule.Key,
                    label = rule.Label,
                    from = $"{previous.Enabled}/{previous.Limit}/{previous.Mode}",
                    to = $"{rule.Enabled}/{rule.Limit}/{rule.Mode}",
                    sensitive = false,
                };
            })
            .Where(change => change.from != change.to)
            .ToArray();

        adminAuditService.AddEntry(
            session.TwitchUserId,
            "workflow-rules.update",
            "season",
            season.Id.ToString(),
            $"Workflow-Regeln fuer Season {season.Year} wurden aktualisiert.",
            new { seasonId = season.Id, season.Year, changes },
            RequestMetadataReader.Read(context));

        await db.SaveChangesAsync(context.RequestAborted);
        return Results.Ok(new AdminWorkflowRulesResponse(after.Select(ToWorkflowRuleDto).ToArray()));
    }

    private static AdminWorkflowRuleDto ToWorkflowRuleDto(WorkflowRuleSetting rule) =>
        new(rule.Key, rule.Label, rule.Enabled, rule.Limit, rule.Mode, rule.Description);
}
