using Backend.Domain;
using Microsoft.EntityFrameworkCore;

namespace Backend.Data;

public static partial class SeedDataBootstrapper
{
    private static async Task EnsureCategoriesAsync(AwardsDbContext db, Season season)
    {
        var seasonCategories = await db.Categories
            .Where(item => item.SeasonId == season.Id)
            .ToArrayAsync();

        foreach (var category in seasonCategories)
        {
            if (!SeedCatalog.LegacyCategorySlugMap.TryGetValue(category.Slug, out var targetSlug))
            {
                continue;
            }

            var target = SeedCatalog.CategorySeeds.First(item => item.Slug == targetSlug);
            category.GroupName = target.GroupName;
            category.Name = target.Name;
            category.Slug = target.Slug;
            category.Description = target.Description;
            category.SortOrder = target.SortOrder;
            category.MaxNomineesPerUser = 3;
        }

        await db.SaveChangesAsync();

        var existing = await db.Categories
            .Where(item => item.SeasonId == season.Id)
            .Select(item => item.Slug)
            .ToArrayAsync();
        var existingSlugs = existing.ToHashSet(StringComparer.OrdinalIgnoreCase);

        foreach (var seed in SeedCatalog.CategorySeeds)
        {
            if (existingSlugs.Contains(seed.Slug))
            {
                continue;
            }

            db.Categories.Add(new Category
            {
                SeasonId = season.Id,
                GroupName = seed.GroupName,
                Name = seed.Name,
                Slug = seed.Slug,
                Description = seed.Description,
                SortOrder = seed.SortOrder,
                MaxNomineesPerUser = 3,
            });
        }

        await db.SaveChangesAsync();
    }

    private static async Task EnsureCandidatesAsync(AwardsDbContext db, Season season, CandidateSeed[] seeds)
    {
        var categories = await db.Categories
            .Where(item => item.SeasonId == season.Id)
            .ToDictionaryAsync(item => item.Slug, StringComparer.OrdinalIgnoreCase);
        var existing = await db.Candidates
            .Where(item => item.SeasonId == season.Id)
            .Select(item => new { item.CategoryId, item.DisplayName, item.ChannelSlug })
            .ToArrayAsync();
        var existingKeys = existing
            .Select(item => $"{item.CategoryId}|{item.DisplayName}|{item.ChannelSlug}".ToLowerInvariant())
            .ToHashSet();

        foreach (var seed in seeds)
        {
            if (!categories.TryGetValue(seed.CategorySlug, out var category))
            {
                continue;
            }

            var key = $"{category.Id}|{seed.DisplayName}|{seed.ChannelSlug}".ToLowerInvariant();
            if (existingKeys.Contains(key))
            {
                continue;
            }

            db.Candidates.Add(new Candidate
            {
                SeasonId = season.Id,
                CategoryId = category.Id,
                DisplayName = seed.DisplayName,
                ChannelSlug = seed.ChannelSlug,
                Platform = seed.Platform,
            });
        }

        await db.SaveChangesAsync();
    }

    private static async Task EnsureWinnersAsync(AwardsDbContext db, Season season, WinnerSeed[] seeds)
    {
        var categories = await db.Categories
            .Where(item => item.SeasonId == season.Id)
            .ToDictionaryAsync(item => item.Slug, StringComparer.OrdinalIgnoreCase);
        var candidates = await db.Candidates
            .Where(item => item.SeasonId == season.Id)
            .ToArrayAsync();
        var existingResults = await db.Results
            .Where(item => item.SeasonId == season.Id)
            .ToArrayAsync();
        foreach (var result in existingResults)
        {
            if (categories.Values.FirstOrDefault(item => item.Id == result.CategoryId) is { } category
                && result.CategoryName != category.Name)
            {
                result.CategoryName = category.Name;
            }
        }

        var existingResultCategoryIds = existingResults.Select(item => item.CategoryId).ToHashSet();

        foreach (var seed in seeds)
        {
            if (!categories.TryGetValue(seed.CategorySlug, out var category) || existingResultCategoryIds.Contains(category.Id))
            {
                continue;
            }

            var candidate = candidates.FirstOrDefault(item =>
                item.CategoryId == category.Id
                && string.Equals(item.DisplayName, seed.DisplayName, StringComparison.OrdinalIgnoreCase));
            if (candidate is null)
            {
                continue;
            }

            db.Results.Add(new AwardResult
            {
                SeasonId = season.Id,
                CategoryId = category.Id,
                CandidateId = candidate.Id,
                CategoryName = category.Name,
            });
        }
    }
}
