using System;
using System.Linq;
using Skender.Stock.Indicators;
using Xunit;
using Xunit.Abstractions;

namespace QuanTAlib.Tests;

public sealed class StcValidationTests : IDisposable
{
    private readonly ValidationTestData _testData;
    private readonly ITestOutputHelper _output;

    public StcValidationTests(ITestOutputHelper output)
    {
        _output = output;
        _testData = new ValidationTestData();
    }

    public void Dispose()
    {
        _testData.Dispose();
    }

    [Fact]
    public void Validate_Skender_Stc_Deviation()
    {
        // Skender's STC implementation uses a "Single Smoothed" approach (Stoch of MACD).
        // QuanTAlib implements the standard "Double Smoothed" approach (Stoch of Stoch of MACD),
        // as originally defined by Schaff.
        //
        // Example mismatch at index 333:
        // QuanTAlib (Double Smoothed) = 50.0
        // Skender (Single Smoothed) = 97.05
        //
        // This test documents this known deviation rather than failing on it.

        const int cycle = 10;
        int fast = 23;
        int slow = 50;

        var sResult = _testData.SkenderQuotes.GetStc(cycle, fast, slow).ToList();
        var qStc = new Stc(kPeriod: cycle, dPeriod: 3, fastLength: fast, slowLength: slow, smoothing: StcSmoothing.Ema);
        var qResult = qStc.Update(_testData.Data);

        // Skender recommends S+C+250 warmup. 50+10+250 = 310.
        int skip = 310;
        double sumSq = 0;
        int count = 0;

        for (int i = skip; i < qResult.Count; i++)
        {
            double sVal = sResult[i].Stc ?? double.NaN;
            double qVal = qResult[i].Value;

            if (!double.IsNaN(sVal) && !double.IsNaN(qVal))
            {
                sumSq += (sVal - qVal) * (sVal - qVal);
                count++;
            }
        }

        double rmse = Math.Sqrt(sumSq / count);
        _output.WriteLine($"Known Methodology Deviation - RMSE: {rmse:F4}");

        // Assert that we are essentially different (RMSE > 5.0 implies significant deviation)
        // If they accidentally matched (e.g. if we broke our logic to match Skender), this should fail.
        Assert.True(rmse > 5.0, "QuanTAlib STC matches Skender STC, which suggests regression to Single Smoothed logic.");

        // Assert values are valid
        for (int i = skip; i < qResult.Count; i++)
        {
            Assert.True(double.IsFinite(qResult[i].Value));
            Assert.InRange(qResult[i].Value, 0, 100);
        }
    }
}
