using Predictalytics.Application.DTOs;

namespace Predictalytics.Application.Services;

/// <summary>Selection inputs for one trader (display DTO + the metrics the showcases rank on).</summary>
public sealed record ShowcaseCandidate(
    TraderDto Dto,
    decimal CopytradingScore,
    decimal TotalPnl,
    decimal Pnl30d,
    decimal? ProfitFactor,
    decimal? ReturnOverMaxDrawdown,
    decimal MaxDrawdownUsd,
    decimal? ConvictionEdgePct,
    decimal CategoryConcentration,
    bool IsSuspectedBot,
    bool IsSnapshotOnly,
    int TotalTrades,
    bool IsPossibleInsider,
    bool IsResolutionFarmer);

/// <summary>One curated dashboard section.</summary>
public sealed record ShowcaseSection(string Key, string Title, string Description, IReadOnlyList<TraderDto> Traders);

/// <summary>
/// Builds the curated "showcase" sections for the dashboard — opinionated, editorial lists that
/// encode the actual selection funnel so a promising trader can be spotted at a glance instead of
/// hand-filtering. Pure function; the ranking IP lives here and is unit-tested.
/// </summary>
public static class ShowcaseBuilder
{
    private const int PerSection = 8;

    public static List<ShowcaseSection> Build(IReadOnlyList<ShowcaseCandidate> candidates)
    {
        var sections = new List<ShowcaseSection>();

        Add(sections, "copy_ready", "Copy-Ready",
            "Solide Kandidaten: gute Kopierbarkeit, Profit-Faktor > 1,3, kein Bot.",
            candidates.Where(c => !c.IsSuspectedBot && !c.IsSnapshotOnly
                    && c.CopytradingScore >= 50 && c.TotalTrades >= 20
                    && (c.ProfitFactor ?? 0m) > 1.3m)
                .OrderByDescending(c => c.CopytradingScore));

        Add(sections, "smooth_operators", "Smooth Operators",
            "Höchste risiko-adjustierte Rendite (Gewinn je Einheit Drawdown).",
            candidates.Where(c => c.TotalPnl > 0m && c.MaxDrawdownUsd > 0m && c.ReturnOverMaxDrawdown.HasValue)
                .OrderByDescending(c => c.ReturnOverMaxDrawdown!.Value));

        Add(sections, "rising_stars", "Rising Stars",
            "Stärkster Gewinn der letzten 30 Tage.",
            candidates.Where(c => !c.IsSuspectedBot && c.Pnl30d > 0m)
                .OrderByDescending(c => c.Pnl30d));

        Add(sections, "high_conviction", "High Conviction",
            "Ihre größten Wetten schlagen die kleinsten — das Sizing trägt Information.",
            candidates.Where(c => !c.IsSuspectedBot && (c.ConvictionEdgePct ?? 0m) > 0m)
                .OrderByDescending(c => c.ConvictionEdgePct!.Value));

        Add(sections, "specialists", "Specialists",
            "Fokussiert auf eine Kategorie und dabei profitabel.",
            candidates.Where(c => c.TotalPnl > 0m && c.CategoryConcentration >= 0.5m)
                .OrderByDescending(c => c.CategoryConcentration));

        Add(sections, "insider_watch", "Insider Watch",
            "Selten aktiv, große Einsätze, statistisch unplausibel gute Longshot-Treffer.",
            candidates.Where(c => c.IsPossibleInsider)
                .OrderByDescending(c => c.TotalPnl));

        Add(sections, "red_flags", "⚠ Red Flags",
            "Hoher PnL, aber verdächtig: überbietet Verlierer, dünne Marge, Bot oder Resolution-Farming.",
            candidates.Where(c => c.TotalPnl > 5000m &&
                    ((c.ConvictionEdgePct ?? 0m) < 0m || (c.ProfitFactor ?? 99m) < 1.1m
                     || c.IsSuspectedBot || c.IsResolutionFarmer))
                .OrderByDescending(c => c.TotalPnl));

        return sections;
    }

    private static void Add(List<ShowcaseSection> sections, string key, string title, string desc,
        IEnumerable<ShowcaseCandidate> ordered)
    {
        var picks = ordered.Take(PerSection).Select(c => c.Dto).ToList();
        if (picks.Count > 0)
            sections.Add(new ShowcaseSection(key, title, desc, picks));
    }
}
