using ExperionCrawler.Infrastructure.Control;
using Xunit;

public class FeedforwardBlocksTests
{
    [Fact]
    public void DeadTime_delays_by_n_samples()
    {
        var d = new DeadTimeBuffer();
        Assert.Equal(10.0, d.Through(10, 10, 2), 3);
        for (int i = 0; i < 4; i++)
            Assert.Equal(10.0, d.Through(20, 10, 2), 3);
        Assert.Equal(10.0, d.Through(20, 10, 2), 3);
        Assert.Equal(20.0, d.Through(20, 10, 2), 3);
    }

    [Fact]
    public void DeadTime_asymmetric_theta_preserves_history()
    {
        // 비대칭 θ(20↔10) 토글 시에도 지연선이 리셋되지 않아야 한다.
        var d = new DeadTimeBuffer();
        double ts = 2;
        for (int i = 0; i < 12; i++) d.Through(0, 20, ts);   // θ=20 → n=10, 0으로 채움
        // 입력을 100으로 바꾸고 θ를 작은 값으로 토글 — 재시드 버그면 즉시 100 누출
        Assert.Equal(0.0, d.Through(100, 10, ts), 3);        // n=5 지연 → 아직 0
        Assert.Equal(0.0, d.Through(100, 20, ts), 3);        // θ 되돌려도 0 (히스토리 보존)
    }

    [Fact]
    public void RateLimiter_clamps_asymmetric_up_down()
    {
        var r = new RateLimiter();
        r.Seed(0);
        Assert.Equal(1, r.Step(100, 60, 600, 1), 3);
        r.Seed(100);
        Assert.Equal(90, r.Step(0, 60, 600, 1), 3);
    }

    [Fact]
    public void FirstOrderLag_reaches_63pct_after_tau()
    {
        var l = new FirstOrderLag();
        l.Seed(0);
        double y = 0; double ts = 1, tau = 10;
        for (int i = 0; i < 10; i++) y = l.Step(1.0, tau, ts);
        Assert.InRange(y, 0.60, 0.66);
    }
}
