using Xunit;
using System;

namespace QuanTAlib.Tests;

public class BopTests
{
    [Fact]
    public void BasicCalculation()
    {
        var bop = new Bop();
        var bar = new TBar(DateTime.UtcNow, 10, 20, 5, 15, 100);
        // Open=10, High=20, Low=5, Close=15
        // Range = 20 - 5 = 15
        // Diff = 15 - 10 = 5
        // BOP = 5 / 15 = 0.3333...

        var result = bop.Update(bar);
        Assert.Equal(1.0 / 3.0, result.Value, 6);
    }

    [Fact]
    public void HighEqualsLow()
    {
        var bop = new Bop();
        var bar = new TBar(DateTime.UtcNow, 10, 10, 10, 10, 100);
        // Range = 0
        // BOP should be 0

        var result = bop.Update(bar);
        Assert.Equal(0, result.Value);
    }

    [Fact]
    public void BuyersDominate()
    {
        var bop = new Bop();
        var bar = new TBar(DateTime.UtcNow, 10, 20, 10, 20, 100);
        // Open=10, High=20, Low=10, Close=20
        // Range = 10
        // Diff = 10
        // BOP = 1

        var result = bop.Update(bar);
        Assert.Equal(1, result.Value);
    }

    [Fact]
    public void SellersDominate()
    {
        var bop = new Bop();
        var bar = new TBar(DateTime.UtcNow, 20, 20, 10, 10, 100);
        // Open=20, High=20, Low=10, Close=10
        // Range = 10
        // Diff = -10
        // BOP = -1

        var result = bop.Update(bar);
        Assert.Equal(-1, result.Value);
    }

    [Fact]
    public void BatchMatchesStreaming()
    {
        var bop = new Bop();
        var bars = new TBarSeries();
        bars.Add(new TBar(DateTime.UtcNow, 10, 20, 5, 15, 100));
        bars.Add(new TBar(DateTime.UtcNow.AddMinutes(1), 15, 25, 10, 20, 100));

        var batchResult = bop.Update(bars);
        
        bop.Reset();
        var streamResult1 = bop.Update(bars[0]);
        var streamResult2 = bop.Update(bars[1]);

        Assert.Equal(batchResult[0].Value, streamResult1.Value);
        Assert.Equal(batchResult[1].Value, streamResult2.Value);
    }
    
    [Fact]
    public void SpanMatchesBatch()
    {
        var bars = new TBarSeries();
        bars.Add(new TBar(DateTime.UtcNow, 10, 20, 5, 15, 100));
        bars.Add(new TBar(DateTime.UtcNow.AddMinutes(1), 15, 25, 10, 20, 100));
        
        var batchResult = Bop.Batch(bars);
        
        var output = new double[bars.Count];
        Bop.Calculate(bars.Open.Values, bars.High.Values, bars.Low.Values, bars.Close.Values, output);
        
        Assert.Equal(batchResult[0].Value, output[0]);
        Assert.Equal(batchResult[1].Value, output[1]);
    }
}
