namespace Predictalytics.Application.Services;

/// <summary>
/// Deeper strategy-fingerprint metrics computed purely from a trader's closed markets and
/// category mix — no new data collection required.
/// </summary>
public static class StrategyMetricsCalculator
{
    /// <summary>
    /// Category concentration via the Herfindahl–Hirschman Index over volume shares.
    /// 1.0 = everything in a single category (specialist); approaches 1/n for an even spread
    /// (generalist). Returns 0 when there is no volume. A specialist's edge is often more
    /// trustworthy inside their niche and more suspect outside it.
    /// </summary>
    public static decimal ComputeConcentration(IEnumerable<decimal> categoryVolumes)
    {
        var vols = categoryVolumes.Where(v => v > 0).ToList();
        var total = vols.Sum();
        if (total <= 0) return 0m;

        decimal hhi = 0m;
        foreach (var v in vols)
        {
            var share = v / total;
            hhi += share * share;
        }
        return System.Math.Round(hhi, 4);
    }

    /// <summary>
    /// Conviction / sizing edge: do the trader's BIGGEST bets outperform their smallest?
    /// Splits closed markets into the top and bottom third by invested capital and returns
    /// (avg return% of the big-bet third) − (avg return% of the small-bet third).
    /// Positive ⇒ their sizing carries information (bigger conviction → better outcome), so a
    /// copier should size-weight them; ≈0 ⇒ size is noise, copy flat; negative ⇒ they overbet
    /// their losers (a red flag). Needs ≥ 6 closed markets; returns null otherwise.
    /// </summary>
    public static decimal? ComputeConvictionEdge(IReadOnlyList<(decimal Invested, decimal ReturnPct)> closedMarkets)
    {
        var valid = closedMarkets.Where(m => m.Invested > 0).OrderBy(m => m.Invested).ToList();
        if (valid.Count < 6) return null;

        int third = valid.Count / 3;
        var smallBets = valid.Take(third).ToList();
        var bigBets = valid.Skip(valid.Count - third).ToList();

        var smallAvg = smallBets.Average(m => m.ReturnPct);
        var bigAvg = bigBets.Average(m => m.ReturnPct);
        return System.Math.Round(bigAvg - smallAvg, 2);
    }
}
