using System.Text.Json.Serialization;

namespace Hc900Crawler.Core.Application.Feedforward;

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum StreamRole { Commanded, LevelDriven, Monitor }

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Confidence { A, B, C }

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ColumnMode { Normal, Recovering, Returning }

public sealed record StreamConfig
{
    public string     Key          { get; init; } = "";
    public string     FlowTag      { get; init; } = "";
    public StreamRole Role         { get; init; } = StreamRole.Monitor;
    public string?    LevelTag     { get; init; }
    public double     TargetCoeff  { get; init; }
    public double     ThetaUpSec   { get; init; }
    public double     ThetaDnSec   { get; init; }
    public double     TauSec       { get; init; }
    public double     SpMin        { get; init; }
    public double     SpMax        { get; init; } = double.MaxValue;
    public double     RateUpPerMin { get; init; } = double.MaxValue;
    public double     RateDnPerMin { get; init; } = double.MaxValue;
    public bool       RefluxFromProduct { get; init; }
    public Confidence Grade        { get; init; } = Confidence.A;
    public bool       IsReflux     { get; init; }
    public double     RecoverySp   { get; init; } = double.NaN;
    public string?    SpNodeId     { get; init; }  // Phase II: OPC UA SP 쓰기 대상 nodeId. null=쓰기 안 함
}

public sealed record ColumnConfig
{
    public int     Id           { get; init; }
    public string  Name         { get; init; } = "";
    public bool    Enabled      { get; init; }
    public bool    AdvisoryOnly { get; init; } = true;
    public string  FeedTag      { get; init; } = "";
    public string? PressureTag  { get; init; }
    public IReadOnlyList<string> LevelTags { get; init; } = Array.Empty<string>();
    public double  ScanSec               { get; init; } = 2.0;
    public double  FeedFilterTauSec      { get; init; } = 300.0;
    public double  FeedMoveThresholdPerMin { get; init; } = 0.0;
    public double  PressFilterTauSec      { get; init; } = 60.0;
    public double  PressureBand          { get; init; } = double.MaxValue;
    public double  SettleSec             { get; init; } = 0.0;
    public double  StaleSec              { get; init; } = 120.0;
    public string? ProductKey            { get; init; } = "P";
    public IReadOnlyList<StreamConfig> Streams { get; init; } = Array.Empty<StreamConfig>();
    public IReadOnlyList<string> TempTags { get; init; } = Array.Empty<string>();
    public string? SensitiveTrayTag { get; init; }
    public double  DTdP            { get; init; } = 0.0;
    public double  PRef            { get; init; } = double.NaN;
    public string? SteamOpTag      { get; init; }
    public bool    ThetaAutoTune   { get; init; }
    public double  BiasMaWindowSec { get; init; } = 6 * 3600;
    public bool    RecoveryEnabled { get; init; }
    public bool    RecoveryAutoArm { get; init; }
    public double  ImbalanceTriggerFrac { get; init; } = 0.10;
    public double  ImbalanceTriggerSec  { get; init; } = 600;
    public double  RecoverySettleSec    { get; init; } = 1800;
    public double  ReturnRampSec        { get; init; } = 600;
    public double  FeedRecoverySp       { get; init; } = 0.0;
    public string? DeltaPTag           { get; init; }
    public double  DeltaPFloodLimit    { get; init; } = double.MaxValue;
    public double  TempHighLimit       { get; init; } = double.MaxValue;   // 온도 HIGH LIMIT(raw) — 전환류 트리거. UI 설정. 1e9=비활성
}

public sealed record TagSample(string Tag, double Value, bool Good, DateTime Timestamp);

public sealed record PvSnapshot(
    TagSample Feed,
    TagSample? Pressure,
    IReadOnlyList<TagSample> Levels,
    IReadOnlyDictionary<string, TagSample> Streams)
{
    public IReadOnlyList<TagSample>? Temps { get; init; }
    public TagSample? SteamOp { get; init; }   // WO-3: TICA.OP (스팀, 부분상관 2번째 입력)
    public TagSample? DeltaP  { get; init; }   // WO-6: 탑 차압(플러딩 트리거)
    public TagSample? BottomPressure { get; init; } // WP6: 탑저 압력(ΔP 합성·국소 PCT용)
}

public sealed record StreamAdvisory(
    string Key, string FlowTag, StreamRole Role,
    double Pv, double? RecommendedSp, double? Gap,
    int Trend,
    bool Valid,
    Confidence Grade,
    string? LevelTag,
    string Note)
{
    public string? GradeReason   { get; init; }
    public double? ThetaSuggestUpSec { get; init; }
    public double? ThetaSuggestDnSec { get; init; }
    public double? ThetaSuggestConf  { get; init; }
    public double? KObsSuggest    { get; init; }
    // WP5 2·3단계: 조성목표 base + 유계 trim (advisory; LevelDriven 드로우용)
    public double? CompositionBase { get; init; }   // 분율×feed (분율=랩수동입력 또는 config K)
    public double? Trim            { get; init; }    // 유계 편차 trim(±clamp, rate제한)
    public double? RecommendedSpComposition { get; init; }  // base + trim
    public string? TrimSource      { get; init; }    // 어느 front에서(하부B/상부D) 유래 + calibrate 표기
    // Phase II: auto-write 결과
    public double?   LastWriteSp    { get; init; }
    public string?   LastWriteError { get; init; }
    public DateTime? LastWriteAt    { get; init; }
}

public sealed record AdvisoryResult(
    int ColumnId, string ColumnName, DateTime ComputedAt,
    bool Enabled, bool Transient, string TransientReason,
    double FeedFiltered,
    IReadOnlyList<StreamAdvisory> Streams,
    double? VLoss, double? Yield, string MassBalanceState)
{
    public ColumnMode Mode { get; init; } = ColumnMode.Normal;
    public string?    ModeReason { get; init; }
    public double?    VLossMa { get; init; }
    public IReadOnlyList<TempPoint>? Temps { get; init; }
    public string?    FrontPositionState { get; init; }
    public string?    FrontTrimAdvice    { get; init; }
    // §10 온도 역전 판정
    public string?    TempProfileState { get; init; }   // 정상/약화/프로파일붕괴/온도역전/정착대기/입력부족
    public string?    InversionPair    { get; init; }
    public double?    TempSpan         { get; init; }
    public double?    TempSpanRef      { get; init; }
    // WP5 1단계: 2-point front (C pivot 기준 상/하 분리)
    public string?    UpperFrontState  { get; init; }   // 상부 ΔT(C−D): 정상/상승/하강/정착대기
    public string?    LowerFrontState  { get; init; }   // 하부 ΔT(C−B): 정상/상승/하강/정착대기
    public double?    UpperFrontMetric { get; init; }
    public double?    LowerFrontMetric { get; init; }
    public double?    FeedRecommendedSp  { get; init; }   // WO-6 전환류 시 FEED 권장(0=차단), 그 외 null
    // Phase II: auto-write 상태
    public bool      AutoWriteActive   { get; init; }
    public double?   WriteGuardBlockedSp { get; init; }  // WriteGuard가 차단한 SP값(표시용)
    public string?   WriteGuardReason  { get; init; }    // 차단 사유
}

public sealed record TempPoint(string Tag, double Raw, double Pct, bool Good);
