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

namespace Backend.Endpoints;

public static partial class PublicEndpoints
{
    private static async Task<IResult> GetOverview(AwardsDbContext db)
    {
        var siteSettings = await db.SiteSettings.AsNoTracking().FirstOrDefaultAsync(item => item.Id == 1);
        var season = await db.Seasons
            .AsNoTracking()
            .Include(item => item.Categories.OrderBy(category => category.SortOrder))
            .ThenInclude(category => category.Candidates)
            .OrderByDescending(item => item.Year)
            .FirstOrDefaultAsync(item => item.IsCurrent);

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

        if (siteSettings is null)
        {
            return Results.Problem("Site settings are missing.");
        }
        var today = DateOnly.FromDateTime(DateTime.UtcNow);
        var showactApplicationsOpenNow = ShowactApplicationSchedule.IsOpenNow(siteSettings, today);

        var latestPublishedWinnerYear = await db.Results
            .AsNoTracking()
            .Where(result => result.Season.WinnersPublishedAt != null)
            .Select(result => (int?)result.Season.Year)
            .MaxAsync();

        var winnerPreviewRows = await db.Results
            .AsNoTracking()
            .Include(result => result.Season)
            .Include(result => result.Candidate)
            .Where(result => result.Season.WinnersPublishedAt != null
                && latestPublishedWinnerYear != null
                && result.Season.Year == latestPublishedWinnerYear.Value)
            .OrderByDescending(result => result.Season.Year)
            .ThenBy(result => result.CategoryName)
            .Take(8)
            .Select(result => new
            {
                Year = result.Season.Year,
                CategoryGroup = result.Category.GroupName,
                result.CategoryName,
                WinnerName = result.Candidate.DisplayName,
                WinnerSlug = result.Candidate.ChannelSlug,
                WinnerPlatform = result.Candidate.Platform,
                ClipUrl = result.Candidate.ClipCompilationUrl,
                ClipTitle = result.Candidate.ClipCompilationTitle,
                ClipPlatform = result.Candidate.ClipCompilationPlatform,
                ClipEmbedStatus = result.Candidate.ClipEmbedStatus,
            })
            .ToArrayAsync();

        var winnerPreviewItems = winnerPreviewRows
            .Select(result => new WinnerPreviewDto(
                result.Year,
                result.CategoryGroup,
                result.CategoryName,
                result.WinnerName,
                result.WinnerSlug,
                result.WinnerPlatform,
                SeasonMappings.BuildProfileUrl(result.WinnerPlatform, result.WinnerSlug),
                result.ClipUrl,
                result.ClipTitle,
                result.ClipPlatform,
                result.ClipEmbedStatus))
            .ToArray();

        var archiveYearRows = await db.Results
            .AsNoTracking()
            .Where(result => result.Season.WinnersPublishedAt != null
                && latestPublishedWinnerYear != null
                && result.Season.Year < latestPublishedWinnerYear.Value)
            .GroupBy(result => result.Season.Year)
            .Select(group => new
            {
                Year = group.Key,
                WinnerCount = group.Count(),
            })
            .OrderByDescending(item => item.Year)
            .ToArrayAsync();

        var archivedWinnerYearRows = await db.ArchivedWinners
            .AsNoTracking()
            .Where(item => latestPublishedWinnerYear == null || item.Year < latestPublishedWinnerYear.Value)
            .GroupBy(item => item.Year)
            .Select(group => new
            {
                Year = group.Key,
                WinnerCount = group.Count(),
            })
            .ToArrayAsync();

        var archiveYears = archiveYearRows
            .Select(item => new ArchiveYearDto(item.Year, item.WinnerCount))
            .Concat(archivedWinnerYearRows.Select(item => new ArchiveYearDto(item.Year, item.WinnerCount)))
            .GroupBy(item => item.Year)
            .Select(group => group.Last())
            .OrderByDescending(item => item.Year)
            .ToArray();

        var phaseKey = SeasonMappings.NormalizePhaseKey(season.CurrentPhase);
        var publicCategories = season.Categories
            .Where(category => ShouldExposePublicCategory(phaseKey, category.Candidates.Count))
            .ToArray();
        var featuredCategories = publicCategories
            .GroupBy(category => category.GroupName.Trim(), StringComparer.OrdinalIgnoreCase)
            .Select(group =>
            {
                var ordered = group
                    .OrderBy(category => category.SortOrder)
                    .ThenBy(category => category.Name, StringComparer.OrdinalIgnoreCase)
                    .ToArray();
                var first = ordered[0];
                var groupDescription = ordered
                    .Select(category => category.Description?.Trim())
                    .FirstOrDefault(description => !string.IsNullOrWhiteSpace(description))
                    ?? string.Empty;
                var maxNomineesPerUser = ordered
                    .Select(category => category.MaxNomineesPerUser)
                    .Where(value => value > 0)
                    .DefaultIfEmpty(3)
                    .Max();

                return new FeaturedCategoryDto(
                    first.Id,
                    first.GroupName,
                    first.GroupName,
                    groupDescription,
                    maxNomineesPerUser);
            })
            .OrderBy(category => publicCategories
                .Where(item => string.Equals(item.GroupName, category.GroupName, StringComparison.OrdinalIgnoreCase))
                .Min(item => item.SortOrder))
            .ThenBy(category => category.GroupName, StringComparer.OrdinalIgnoreCase)
            .ToArray();
        var response = new OverviewResponse(
            season.Id,
            season.Year,
            season.Name,
            season.ShowDate,
            season.ShowStartsAt,
            season.CurrentPhase,
            season.IsCommunityOnly,
            "Twitch",
            new[]
            {
                new TimelineItem("nomination", "Nominierung", season.NominationStartsAt, season.NominationEndsAt, SeasonMappings.ResolveTimelineState("nomination", phaseKey)),
                new TimelineItem("voting", "Voting", season.VotingStartsAt, season.VotingEndsAt, SeasonMappings.ResolveTimelineState("voting", phaseKey)),
                new TimelineItem("preparation", "Aufbereitung", season.ReviewStartsAt, season.ReviewEndsAt, SeasonMappings.ResolveTimelineState("preparation", phaseKey)),
                new TimelineItem("show", "Award Show", season.ShowDate, season.ShowDate, SeasonMappings.ResolveTimelineState("show", phaseKey)),
            },
            featuredCategories,
            winnerPreviewItems,
            archiveYears,
            new PublicSiteContentDto(
                siteSettings.HostDisplayName,
                siteSettings.HostTagline,
                siteSettings.HostArtistName,
                AdminSiteSettingsEndpoints.BuildHostImageUrl(siteSettings),
                siteSettings.NewsletterUrl,
                siteSettings.ShareXUrl,
                siteSettings.ShareDiscordUrl,
                siteSettings.PrivacyEmail,
                siteSettings.PrivacyPolicyContent,
                SeasonMappings.NormalizePlainTextContent(siteSettings.AwardsSectionTitle),
                SeasonMappings.NormalizePlainTextContent(siteSettings.AwardsSectionDescription),
                SeasonMappings.NormalizePlainTextContent(siteSettings.SubcategoriesSectionTitle),
                SeasonMappings.NormalizePlainTextContent(siteSettings.SubcategoriesSectionDescription),
                new PublicStreamBannerContentDto(
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerEyebrow),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerTitle),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerText),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerLiveButtonLabel),
                    SeasonMappings.NormalizeSeasonStreamUrl(siteSettings.StreamBannerLiveButtonUrl),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerLockedButtonLabel),
                    siteSettings.StreamBannerUseCompletedContent,
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerCompletedEyebrow),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerCompletedTitle),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerCompletedText),
                    SeasonMappings.NormalizePlainTextContent(siteSettings.StreamBannerCompletedButtonLabel),
                    SeasonMappings.NormalizeSeasonStreamUrl(siteSettings.StreamBannerCompletedButtonUrl)),
                SeasonMappings.ReadSocialLinks(siteSettings),
                SeasonMappings.BuildFooterLinks(siteSettings)),
            new PublicFeatureFlagsDto(
                siteSettings.ClipSubmissionsEnabled,
                siteSettings.ClipReviewEnabled,
                string.IsNullOrWhiteSpace(siteSettings.ClipSubmissionDisabledMessage)
                    ? "Clip-Einreichungen sind aktuell geschlossen."
                    : siteSettings.ClipSubmissionDisabledMessage,
                showactApplicationsOpenNow,
                siteSettings.ShowactApplicationStartsAt,
                siteSettings.ShowactApplicationEndsAt,
                string.IsNullOrWhiteSpace(siteSettings.ShowactApplicationDisabledMessage)
                    ? "Showact-Bewerbungen sind aktuell geschlossen."
                    : siteSettings.ShowactApplicationDisabledMessage,
                siteSettings.SponsorsVisible,
                siteSettings.ShowactFormSchemaJson ?? "[]"),
            SeasonMappings.ReadFaqItems(siteSettings));

        return Results.Ok(response);
    }
}
