using GameList.Data;
using GameList.Domain;
using Microsoft.EntityFrameworkCore;
using GameList.Infrastructure;

namespace GameList.Endpoints;

public static class ResultsEndpoints
{
    public static void MapResultsEndpoints(this IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/api/results")
            .RequireAuthorization()
            .AddEndpointFilter(new PhaseRequirementFilter(Phase.Results));

        group.MapGet(
            "/",
            async (HttpContext ctx, AppDbContext db) =>
            {
                var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db);
                if (player is null)
                    return Results.Unauthorized();
                var appState = await db.AppState.AsNoTracking().FirstAsync();
                if (!appState.ResultsOpen)
                    return Results.BadRequest(new { error = "Results are locked until the admin enables them." });
                var phase = await EndpointHelpers.GetPhase(db, player.Id);
                if (phase != Phase.Results)
                    return EndpointHelpers.PhaseMismatch(Phase.Results, phase);

                var results = await db
                    .Suggestions.AsNoTracking()
                    .Include(s => s.Player)
                    .Include(s => s.Votes)
                    .Select(s => new
                    {
                        s.Id,
                        s.Name,
                        Author = s.Player!.DisplayName,
                        s.MinPlayers,
                        s.MaxPlayers,
                        Total = s.Votes.Sum(v => v.Score),
                        s.Votes.Count,
                        Average = s.Votes.Count == 0 ? 0 : s.Votes.Average(v => v.Score),
                        Votes = s.Votes.Select(v => v.Score).ToList(),
                        MyVote = s.Votes
                            .Where(v => v.PlayerId == player.Id)
                            .Select(v => (int?)v.Score)
                            .FirstOrDefault(),
                        s.ScreenshotUrl,
                        s.YoutubeUrl,
                        s.GameUrl,
                        s.Description,
                        s.Genre,
                        s.ParentSuggestionId
                    })
                    .OrderByDescending(r => r.Average)
                    .ToListAsync();

                var rootIndex = EndpointHelpers.BuildLinkRoots(results.Select(r => (r.Id, r.ParentSuggestionId)));
                var nameLookup = results.ToDictionary(r => r.Id, r => r.Name);

                var shaped = results.Select(r =>
                {
                    var linkedIds = EndpointHelpers.LinkedIdsFor(r.Id, rootIndex)
                        .Where(id => id != r.Id)
                        .ToList();

                    return new
                    {
                        r.Id,
                        r.Name,
                        r.Author,
                        r.MinPlayers,
                        r.MaxPlayers,
                        r.Total,
                        r.Count,
                        r.Average,
                        r.Votes,
                        r.MyVote,
                        r.ScreenshotUrl,
                        r.YoutubeUrl,
                        r.GameUrl,
                        r.Description,
                        r.Genre,
                        r.ParentSuggestionId,
                        LinkedIds = linkedIds,
                        LinkedTitles = linkedIds
                            .Where(nameLookup.ContainsKey)
                            .Select(id => nameLookup[id])
                            .ToList()
                    };
                });

                return Results.Ok(shaped);
            }
        );
    }
}
