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

namespace GameList.Endpoints;

internal sealed class ResultsWorkflowService(AppDbContext db)
{
    public async Task<IResult> GetResultsAsync(Player player)
    {
        var appState = await db.AppState.AsNoTracking().FirstAsync();
        if (!appState.ResultsOpen)
            return EndpointHelpers.BadRequestError("Results are locked until the admin enables them.");

        var phase = await EndpointHelpers.GetCurrentPhaseAsync(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();

            var linkedTitles = linkedIds
                .Where(nameLookup.ContainsKey)
                .Select(id => nameLookup[id])
                .ToList();

            return new ResultItemDto(
                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,
                linkedTitles
            );
        });

        return Results.Ok(shaped);
    }
}
