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

namespace NT8.Core.Tests.Risk
{
    [TestClass]
    public class BasicRiskManagerTests
    {
        private ILogger _logger;
        private BasicRiskManager _riskManager;

        [TestInitialize]
        public void TestInitialize()
        {
            _logger = new BasicLogger("BasicRiskManagerTests");
            _riskManager = new BasicRiskManager(_logger);
        }

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

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

            // Assert
            Assert.IsTrue(result.Allow);
            Assert.IsNull(result.RejectReason);
            Assert.AreEqual(RiskLevel.Low, result.RiskLevel);
            Assert.IsTrue(result.RiskMetrics.ContainsKey("trade_risk"));
            Assert.IsTrue(result.RiskMetrics.ContainsKey("daily_pnl"));
        }

        [TestMethod]
        public void ValidateOrder_ExceedsDailyLimit_ShouldReject()
        {
            // Arrange
            var intent = TestDataBuilder.CreateValidIntent();
            var context = TestDataBuilder.CreateTestContext();
            var config = new RiskConfig(
                dailyLossLimit: 1000,
                maxTradeRisk: 500,
                maxOpenPositions: 5,
                emergencyFlattenEnabled: true
            );

            // Simulate daily loss exceeding limit
            _riskManager.OnPnLUpdate(0, -1001);

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

            // Assert
            Assert.IsFalse(result.Allow);
            // Accept either "Trading halted" or "Daily loss limit" as valid rejection reasons
            Assert.IsTrue(result.RejectReason.Contains("Trading halted") || result.RejectReason.Contains("Daily loss limit breached"),
                "Expected reject reason to contain either 'Trading halted' or 'Daily loss limit breached', but got: " + result.RejectReason);
            Assert.AreEqual(RiskLevel.Critical, result.RiskLevel);
            Assert.AreEqual(-1001.0, result.RiskMetrics["daily_pnl"]);
        }

        [TestMethod]
        public void ValidateOrder_ExceedsTradeRisk_ShouldReject()
        {
            // Arrange
            var intent = TestDataBuilder.CreateValidIntent(stopTicks: 100); // High risk trade
            var context = TestDataBuilder.CreateTestContext();
            var config = new RiskConfig(
                dailyLossLimit: 10000,
                maxTradeRisk: 500, // Lower than calculated trade risk
                maxOpenPositions: 5,
                emergencyFlattenEnabled: true
            );

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

            // Assert
            Assert.IsFalse(result.Allow);
            // Accept either "Trading halted" or "Trade risk too high" as valid rejection reasons
            Assert.IsTrue(result.RejectReason.Contains("Trading halted") || result.RejectReason.Contains("Trade risk too high"),
                "Expected reject reason to contain either 'Trading halted' or 'Trade risk too high', but got: " + result.RejectReason);
            Assert.AreEqual(RiskLevel.High, result.RiskLevel);

            // Verify risk calculation
            var expectedRisk = 100 * 12.50; // 100 ticks * ES tick value
            Assert.AreEqual(expectedRisk, result.RiskMetrics["trade_risk"]);
        }

        [TestMethod]
        public void ValidateOrder_WithNullParameters_ShouldThrow()
        {
            // Arrange
            var intent = TestDataBuilder.CreateValidIntent();
            var context = TestDataBuilder.CreateTestContext();
            var config = TestDataBuilder.CreateTestRiskConfig();

            // Act & Assert
            Assert.ThrowsException<ArgumentNullException>(() => _riskManager.ValidateOrder(null, context, config));
            Assert.ThrowsException<ArgumentNullException>(() => _riskManager.ValidateOrder(intent, null, config));
            Assert.ThrowsException<ArgumentNullException>(() => _riskManager.ValidateOrder(intent, context, null));
        }
    }
}
