using Microsoft.VisualStudio.TestTools.UnitTesting;
using NT8.Core.Common.Models;
using NT8.Core.Logging;
using NT8.Core.Risk;
using System;
using System.Collections.Generic;

namespace NT8.Core.Tests.Risk
{
    [TestClass]
    public class AdvancedRiskManagerTests
    {
        private AdvancedRiskManager _advancedRiskManager;

        [TestInitialize]
        public void TestInitialize()
        {
            _advancedRiskManager = CreateManager(
                weeklyLossLimit: 10000,
                trailingDrawdownLimit: 5000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 100000,
                tradingTimeWindows: new List<TradingTimeWindow>());
        }

        [TestMethod]
        public void ValidateOrder_AllChecksPass_ShouldAllow()
        {
            // Arrange
            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = TestDataBuilder.CreateTestContext(symbol: "ES");
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Act
            var result = _advancedRiskManager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsTrue(result.Allow);
            Assert.IsNull(result.RejectReason);
            Assert.IsTrue(result.RiskMetrics.ContainsKey("weekly_pnl"));
            Assert.IsTrue(result.RiskMetrics.ContainsKey("trailing_drawdown"));
            Assert.IsTrue(result.RiskMetrics.ContainsKey("active_strategies"));
        }

        [TestMethod]
        public void ValidateOrder_WeeklyLossLimitBreached_ShouldReject()
        {
            // Arrange
            var manager = CreateManager(
                weeklyLossLimit: 5000,
                trailingDrawdownLimit: 50000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 100000,
                tradingTimeWindows: new List<TradingTimeWindow>());

            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = TestDataBuilder.CreateTestContext(symbol: "ES");
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Keep daily PnL above BasicRiskManager emergency threshold (-900),
            // but accumulate enough weekly loss to breach advanced weekly limit.
            for (var i = 0; i < 9; i++)
            {
                manager.OnPnLUpdate(50000, -600);
            }

            // Act
            var result = manager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsFalse(result.Allow);
            Assert.IsTrue(result.RejectReason.Contains("Weekly loss limit breached"));
            Assert.AreEqual(RiskLevel.Critical, result.RiskLevel);
        }

        [TestMethod]
        public void ValidateOrder_TrailingDrawdownBreached_ShouldReject()
        {
            // Arrange
            var manager = CreateManager(
                weeklyLossLimit: 100000,
                trailingDrawdownLimit: 1000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 100000,
                tradingTimeWindows: new List<TradingTimeWindow>());

            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = new StrategyContext(
                symbol: "ES",
                currentTime: DateTime.UtcNow,
                currentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
                account: new AccountInfo(48000, 48000, 0, 0, DateTime.UtcNow),
                session: new MarketSession(DateTime.Today.AddHours(9.5), DateTime.Today.AddHours(16), true, "RTH"),
                customData: new Dictionary<string, object>());
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Build peak equity in manager state, then validate with lower account equity in context.
            manager.OnPnLUpdate(50000, 100);

            // Act
            var result = manager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsFalse(result.Allow);
            Assert.IsTrue(result.RejectReason.Contains("Trailing drawdown limit breached"));
            Assert.AreEqual(RiskLevel.Critical, result.RiskLevel);
        }

        [TestMethod]
        public void ValidateOrder_CrossStrategyExposureExceeded_ShouldReject()
        {
            // Arrange
            var manager = CreateManager(
                weeklyLossLimit: 100000,
                trailingDrawdownLimit: 50000,
                maxCrossStrategyExposure: 50,
                maxCorrelatedExposure: 100000,
                tradingTimeWindows: new List<TradingTimeWindow>());

            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = TestDataBuilder.CreateTestContext(symbol: "ES");
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Act
            var result = manager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsFalse(result.Allow);
            Assert.IsTrue(result.RejectReason.Contains("Cross-strategy exposure limit exceeded"));
            Assert.AreEqual(RiskLevel.High, result.RiskLevel);
        }

        [TestMethod]
        public void ValidateOrder_CorrelatedExposureExceeded_ShouldReject()
        {
            // Arrange
            var manager = CreateManager(
                weeklyLossLimit: 100000,
                trailingDrawdownLimit: 50000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 50,
                tradingTimeWindows: new List<TradingTimeWindow>());

            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = TestDataBuilder.CreateTestContext(symbol: "ES");
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Act
            var result = manager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsFalse(result.Allow);
            Assert.IsTrue(result.RejectReason.Contains("Correlated exposure limit exceeded"));
            Assert.AreEqual(RiskLevel.High, result.RiskLevel);
        }

        [TestMethod]
        public void ValidateOrder_OutsideTradingWindow_ShouldReject()
        {
            // Arrange
            var now = DateTime.UtcNow.TimeOfDay;
            var windows = new List<TradingTimeWindow>();
            windows.Add(new TradingTimeWindow(now.Add(TimeSpan.FromHours(1)), now.Add(TimeSpan.FromHours(2))));

            var manager = CreateManager(
                weeklyLossLimit: 100000,
                trailingDrawdownLimit: 50000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 100000,
                tradingTimeWindows: windows);

            var intent = TestDataBuilder.CreateValidIntent(symbol: "ES", stopTicks: 8);
            var context = TestDataBuilder.CreateTestContext(symbol: "ES");
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Act
            var result = manager.ValidateOrder(intent, context, config);

            // Assert
            Assert.IsFalse(result.Allow);
            Assert.IsTrue(result.RejectReason.Contains("outside allowed trading time windows"));
            Assert.AreEqual(RiskLevel.Medium, result.RiskLevel);
        }

        private static AdvancedRiskManager CreateManager(
            double weeklyLossLimit,
            double trailingDrawdownLimit,
            double? maxCrossStrategyExposure,
            double? maxCorrelatedExposure,
            List<TradingTimeWindow> tradingTimeWindows)
        {
            ILogger logger = new BasicLogger("AdvancedRiskManagerTests");
            var basicRiskManager = new BasicRiskManager(logger);
            var advancedConfig = new AdvancedRiskConfig(
                weeklyLossLimit,
                trailingDrawdownLimit,
                maxCrossStrategyExposure,
                TimeSpan.FromMinutes(30),
                maxCorrelatedExposure,
                tradingTimeWindows);

            return new AdvancedRiskManager(logger, basicRiskManager, advancedConfig);
        }
    }
}
