using System;
using System.Collections.Generic;
using ExperionCrawler.Core.Application.Feedforward;
using ExperionCrawler.Infrastructure.Control;
using Xunit;

namespace ExperionCrawler.Tests;

// WP5 1단계: 2-point front (C=제품 pivot=temps[n-2]). 상부=ΔT(C−D), 하부=ΔT(C−B).
// temp_tags 하단→상단 [A,B,C,D]. dtdp=0 → pct=raw. 한 섹션만 perturb 시 그 front만 반응.
public class FeedforwardFront2PointTests
{
    private static ColumnConfig Cfg() => new()
    {
        Id = 1, Name = "C-F2", Enabled = true, FeedTag = "f", ProductKey = "P", ScanSec = 2,
        DTdP = 0.0, PRef = double.NaN, PressureTag = null, FeedMoveThresholdPerMin = 0.0,
        TempTags = new[] { "a", "b", "c", "d" },
        Streams = new[] { new StreamConfig { Key = "P", FlowTag = "ficq-6118", Role = StreamRole.Commanded, Grade = Confidence.A, TargetCoeff = 0.95 } }
    };

    private static PvSnapshot Snap(double a, double b, double c, double d) => new(
        new TagSample("f", 100, true, DateTime.UtcNow), null, Array.Empty<TagSample>(),
        new Dictionary<string, TagSample> { ["P"] = new TagSample("ficq-6118", 95, true, DateTime.UtcNow) })
        {
            Temps = new[]
            {
                new TagSample("a", a, true, DateTime.UtcNow), new TagSample("b", b, true, DateTime.UtcNow),
                new TagSample("c", c, true, DateTime.UtcNow), new TagSample("d", d, true, DateTime.UtcNow)
            }
        };

    [Fact]
    public void Lower_front_isolates_from_upper()
    {
        var engine = new FeedforwardEngine(); var st = new ColumnState();
        // 정상 단조 A110>B105>C100>D90 으로 baseline 시드
        for (int i = 0; i < 5; i++) engine.Tick(Cfg(), Snap(110, 105, 100, 90), st, DateTime.UtcNow);
        // 하부만 perturb: B 강하(105→95) → C−B 증가 → 하부 "상승". 상부(C,D 불변) "정상"
        var res = engine.Tick(Cfg(), Snap(110, 95, 100, 90), st, DateTime.UtcNow);
        Assert.Equal("상승", res.LowerFrontState);
        Assert.Equal("정상", res.UpperFrontState);
    }

    [Fact]
    public void Upper_front_isolates_from_lower()
    {
        var engine = new FeedforwardEngine(); var st = new ColumnState();
        for (int i = 0; i < 5; i++) engine.Tick(Cfg(), Snap(110, 105, 100, 90), st, DateTime.UtcNow);
        // 상부만 perturb: D 가열(90→98) → C−D 감소 → 상부 "하강". 하부(C,B 불변) "정상"
        var res = engine.Tick(Cfg(), Snap(110, 105, 100, 98), st, DateTime.UtcNow);
        Assert.Equal("하강", res.UpperFrontState);
        Assert.Equal("정상", res.LowerFrontState);
    }

    [Fact]
    public void Metrics_exposed()
    {
        var engine = new FeedforwardEngine(); var st = new ColumnState();
        var res = engine.Tick(Cfg(), Snap(110, 105, 100, 90), st, DateTime.UtcNow);
        Assert.Equal(10.0, res.UpperFrontMetric!.Value, 6);   // C−D = 100−90
        Assert.Equal(-5.0, res.LowerFrontMetric!.Value, 6);   // C−B = 100−105
    }
}
