using Xunit;
using KArtSell.Modules.ModelOperations.ShadowRun;

namespace KArtSell.Integration.Tests;

/// <summary>
/// Phase segmentation tests: regime classification + metrics per phase.
/// Tests use production implementations from ShadowRun module.
/// </summary>
public sealed class PhaseSegmentationTests
{
    [Fact]
    public void RegimeClassifier_BullTrend_ClassifiesAllAsBull()
    {
        // Arrange: Simulate bull market (5% increase)
        var bars = new List<(DateOnly, decimal)>
        {
            (new DateOnly(2024, 1, 2), 100m),
            (new DateOnly(2024, 1, 3), 101m),
            (new DateOnly(2024, 1, 4), 102m),
            (new DateOnly(2024, 1, 5), 103m),
            (new DateOnly(2024, 1, 8), 104m),
            (new DateOnly(2024, 1, 9), 105m),
        };

        // Act
        var regimes = RegimeClassifier.Classify(bars);

        // Assert
        Assert.All(regimes, regime => Assert.Equal(MarketRegime.Bull, regime.Regime));
    }

    [Fact]
    public void RegimeClassifier_BearTrend_ClassifiesAllAsBear()
    {
        // Arrange: Simulate bear market (4.76% decrease)
        var bars = new List<(DateOnly, decimal)>
        {
            (new DateOnly(2024, 1, 2), 105m),
            (new DateOnly(2024, 1, 3), 104m),
            (new DateOnly(2024, 1, 4), 103m),
            (new DateOnly(2024, 1, 5), 102m),
            (new DateOnly(2024, 1, 8), 101m),
            (new DateOnly(2024, 1, 9), 100m),
        };

        // Act
        var regimes = RegimeClassifier.Classify(bars);

        // Assert
        Assert.All(regimes, regime => Assert.Equal(MarketRegime.Bear, regime.Regime));
    }

    [Fact]
    public void RegimeClassifier_Sideways_ClassifiesAllAsSideways()
    {
        // Arrange: Simulate sideways market (0% net change)
        var bars = new List<(DateOnly, decimal)>
        {
            (new DateOnly(2024, 1, 2), 100m),
            (new DateOnly(2024, 1, 3), 101m),
            (new DateOnly(2024, 1, 4), 99m),
            (new DateOnly(2024, 1, 5), 102m),
            (new DateOnly(2024, 1, 8), 98m),
            (new DateOnly(2024, 1, 9), 100m),
        };

        // Act
        var regimes = RegimeClassifier.Classify(bars);

        // Assert
        Assert.All(regimes, regime => Assert.Equal(MarketRegime.Sideways, regime.Regime));
    }

    [Fact]
    public void PhaseMetrics_BullPhase_CalculatesCorrectMetrics()
    {
        // Arrange: 5 winning days
        var dailyReturns = new List<decimal> { 0.01m, 0.02m, 0.01m, 0.005m, 0.015m };

        // Act
        var metrics = PhaseMetricsCalculator.Calculate(dailyReturns);

        // Assert
        Assert.Equal(5, metrics.TradingDays);
        Assert.True(metrics.WinRate > 0 && metrics.WinRate <= 1);
        Assert.True(metrics.Return > 0, "Bull phase should have positive return");
    }

    [Fact]
    public void PhaseMetrics_EmptyPhase_ReturnsZeros()
    {
        // Arrange: No returns
        var dailyReturns = new List<decimal>();

        // Act
        var metrics = PhaseMetricsCalculator.Calculate(dailyReturns);

        // Assert
        Assert.Equal(0, metrics.TradingDays);
        Assert.Equal(0m, metrics.Return);
        Assert.Equal(0m, metrics.Sharpe);
    }

    [Fact]
    public void PhaseMetrics_MixedReturns_CalculatesWinRate()
    {
        // Arrange: 3 wins, 2 losses
        var dailyReturns = new List<decimal> { 0.01m, -0.005m, 0.02m, -0.01m, 0.015m };

        // Act
        var metrics = PhaseMetricsCalculator.Calculate(dailyReturns);

        // Assert
        Assert.Equal(0.6m, metrics.WinRate); // 3/5 = 60%
    }

    [Fact]
    public void PhaseBreakdown_MultiPhase_SumsDaysCorrectly()
    {
        // Arrange: Multi-phase portfolio (bull days + bear days)
        var dailyReturns = new List<(DateOnly, decimal)>
        {
            (new DateOnly(2024, 1, 2), 0.01m),
            (new DateOnly(2024, 1, 3), 0.02m),
            (new DateOnly(2024, 1, 4), -0.005m),
            (new DateOnly(2024, 1, 5), 0.015m),
            (new DateOnly(2024, 1, 8), -0.01m),
        };

        // Act
        var breakdown = PhaseSegmentation.Segment(dailyReturns);

        // Assert: Sum of trading days equals input count
        var totalDays = breakdown.BullMarket.TradingDays
                      + breakdown.BearMarket.TradingDays
                      + breakdown.Sideways.TradingDays
                      + breakdown.HighVolatility.TradingDays;
        Assert.Equal(dailyReturns.Count, totalDays);
    }

    [Fact]
    public void Segmentation_ReturnsValidMetrics_AllFieldsPopulated()
    {
        // Arrange: Minimal multi-day scenario
        var dailyReturns = new List<(DateOnly, decimal)>
        {
            (new DateOnly(2024, 1, 2), 0.01m),
            (new DateOnly(2024, 1, 3), 0.02m),
            (new DateOnly(2024, 1, 4), -0.005m),
        };

        // Act
        var breakdown = PhaseSegmentation.Segment(dailyReturns);

        // Assert: All metrics non-null and valid
        Assert.NotNull(breakdown.BullMarket);
        Assert.NotNull(breakdown.BearMarket);
        Assert.NotNull(breakdown.Sideways);
        Assert.NotNull(breakdown.HighVolatility);

        Assert.True(breakdown.BullMarket.WinRate >= 0 && breakdown.BullMarket.WinRate <= 1);
        Assert.True(breakdown.BullMarket.Sharpe >= -5 && breakdown.BullMarket.Sharpe <= 5);
    }
}
