using System;
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;

namespace QuantEngine.Core.Tests
{
    public class ExitDecisionsTests
    {
        [Fact]
        public void ComputeStopPriceCore_AtrBased_ReturnsCorrectPrice()
        {
            // ATR 2.0배 기반 계산 검증
            var res = ExitDecisions.ComputeStopPriceCore(
                entryPrice: 100000,
                atr20: 3000,
                currentPrice: 100000,
                atrMultiplier: 2.0
            );

            Assert.Equal("PASS", res.StopPriceStatus);
            Assert.Equal(94000, res.StopPrice); // 100000 - 3000 * 2.0 = 94000
        }

        [Fact]
        public void ComputeStopPriceCore_FallbackPrice_Returns8PercentDown()
        {
            // 결측인 경우 8% 하락 폴백 가격으로 설정 검증
            var res = ExitDecisions.ComputeStopPriceCore(
                entryPrice: 100000,
                atr20: null,
                currentPrice: null,
                atrMultiplier: null
            );

            Assert.Contains("DATA_MISSING", res.StopPriceStatus);
            Assert.Equal(92000, res.StopPrice); // 100000 * 0.92 = 92000
        }

        [Fact]
        public void ComputeStopPriceCore_AtrPercentBased_SetsCorrectMultiplier()
        {
            // ATR 비율에 따른 동적 승수 선택 검증 (atr20=10000, current=100000 -> atr20Pct = 10% >= 8% -> multiplier = 2.0)
            var res = ExitDecisions.ComputeStopPriceCore(
                entryPrice: 100000,
                atr20: 10000,
                currentPrice: 100000,
                atrMultiplier: null
            );

            Assert.Equal("PASS", res.StopPriceStatus);
            Assert.Equal(2.0, res.AtrMultiplier);
            Assert.Equal(92000, res.StopPrice); // Max(92000, 100000 - 10000 * 2.0) = Max(92000, 80000) = 92000
        }

        [Theory]
        [InlineData("STOP_OR_TIME_EXIT_READY", 4, "EXIT_100", "STOP_OR_TIME_EXIT_READY")]
        [InlineData("NORMAL_TRADING", 4, "EXIT_100", "RW_EXIT_STRONG")]
        [InlineData("NORMAL_TRADING", 1, "REGIME_TRIM_50", "REGIME_RISK_OFF")] // REGIME_PRELIM="RISK_OFF"
        [InlineData("NORMAL_TRADING", 1, "TRIM_70", "TIMING_EXIT_SCORE")]    // timingExitScore = 75
        [InlineData("NORMAL_TRADING", 1, "TRIM_50", "TRAILING_STOP_BREACH")] // trailingStopBreach = true
        [InlineData("NORMAL_TRADING", 0, "TIME_EXIT_100", "TIME_STOP_EXPIRED")] // daysToTimeStop = 0
        public void ComputeStopActionLadder_Scenarios_ReturnExpectedAction(
            string timingAction,
            int rwPartial,
            string expectedAction,
            string expectedReason)
        {
            var ctx = new Dictionary<string, object>
            {
                { "timingAction", timingAction },
                { "rw_partial", rwPartial },
                { "REGIME_PRELIM", expectedReason == "REGIME_RISK_OFF" ? "RISK_OFF" : "RISK_ON" },
                { "timingExitScore", expectedReason == "TIMING_EXIT_SCORE" ? 75.0 : 0.0 },
                { "trailingStopBreach", expectedReason == "TRAILING_STOP_BREACH" },
                { "daysToTimeStop", expectedReason == "TIME_STOP_EXPIRED" ? 0 : 9999 }
            };

            var res = ExitDecisions.ComputeStopActionLadder(ctx);

            Assert.Equal(expectedAction, res.Action);
            Assert.Equal(expectedReason, res.Reason);
        }

        [Theory]
        [InlineData("EVENT_SHOCK", 5.0, 3.5)]
        [InlineData("RISK_OFF", 7.0, 5.0)]
        [InlineData("SECULAR_LEADER_RISK_ON", 13.0, 9.0)]
        [InlineData("RISK_ON", 12.0, 8.5)]
        [InlineData("NEUTRAL", 10.0, 7.0)]
        public void ComputeDynamicHeatThresholds_Regimes_ReturnCorrectThresholds(
            string regime,
            double expectedHard,
            double expectedHalve)
        {
            var res = ExitDecisions.ComputeDynamicHeatThresholds(regime);
            Assert.Equal(expectedHard, res.HardBlock);
            Assert.Equal(expectedHalve, res.Halve);
        }
    }
}
