using Predictalytics.Application.Interfaces;
using Predictalytics.Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Predictalytics.Infrastructure.Services;

public class CopytradingBacktestHarness : ICopytradingBacktestHarness
{
    private readonly ICopytradingEstimator _estimator;

    public CopytradingBacktestHarness(ICopytradingEstimator estimator)
    {
        _estimator = estimator;
    }

    public async Task<List<BacktestResult>> RunLatencySweepAsync(Trader trader, IReadOnlyList<Trade> trades, CancellationToken ct = default)
    {
        var results = new List<BacktestResult>();
        int[] latencies = new[] { 0, 10, 30, 60 };

        var events = _estimator.ClusterTradesIntoEvents(trades, TimeSpan.FromHours(24));
        var buyEvents = events.Where(e => e.Side == Predictalytics.Domain.Enums.TradeSide.Buy).ToList();

        foreach (int latency in latencies)
        {
            decimal followerPnl = 0;
            decimal traderPnl = 0;
            decimal totalRisked = 0;

            foreach (var e in buyEvents)
            {
                var sampleTrade = e.ConstituentTrades.First();
                var market = sampleTrade.DbMarket;
                var outcome = sampleTrade.MarketOutcome;

                decimal resolutionPrice = 0;
                bool isResolved = market?.IsResolved ?? false;

                if (isResolved)
                {
                    resolutionPrice = string.Equals(market?.ResolutionOutcome, sampleTrade.Outcome, StringComparison.OrdinalIgnoreCase) ? 1.0m : 0.0m;
                }
                else
                {
                    resolutionPrice = outcome?.CurrentPrice ?? e.AveragePrice;
                }

                // Calculate Trader PnL
                decimal entryPrice = e.AveragePrice;
                decimal size = e.TotalSize;
                decimal eventTraderPnl = (resolutionPrice - entryPrice) * size;
                
                traderPnl += eventTraderPnl;
                totalRisked += entryPrice * size;

                // Calculate Follower PnL
                decimal eventFollowerPnl = 0;
                
                foreach (var t in e.ConstituentTrades)
                {
                    // For latency 0, we assume perfect fill (which is unrealistic, but serves as baseline)
                    decimal followerFill = t.Price;

                    if (latency > 0)
                    {
                        var fill = await _estimator.EstimateFollowerFillPriceAsync(t, latency, ct);
                        if (fill.HasValue)
                        {
                            followerFill = fill.Value;
                        }
                    }

                    eventFollowerPnl += (resolutionPrice - followerFill) * t.Size;
                }
                
                followerPnl += eventFollowerPnl;
            }

            decimal alphaDecay = 0;
            if (traderPnl != 0)
            {
                alphaDecay = (traderPnl - followerPnl) / Math.Abs(traderPnl) * 100m;
            }

            results.Add(new BacktestResult
            {
                LatencySeconds = latency,
                TraderPnl = traderPnl,
                HypotheticalFollowerPnl = followerPnl,
                AlphaDecayPercentage = alphaDecay
            });
        }

        return results;
    }
}
