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

namespace NT8.Integration.Tests
{
    /// <summary>
    /// Integration tests for Phase 2 risk + sizing workflow.
    /// </summary>
    [TestClass]
    public class RiskSizingIntegrationTests
    {
        /// <summary>
        /// Verifies that a valid intent passes advanced risk and then receives a valid size.
        /// </summary>
        [TestMethod]
        public void EndToEnd_ValidIntent_RiskAllows_ThenSizingReturnsContracts()
        {
            // Arrange
            var logger = new BasicLogger("RiskSizingIntegrationTests");
            var basicRiskManager = new BasicRiskManager(logger);
            var advancedRiskManager = new AdvancedRiskManager(
                logger,
                basicRiskManager,
                CreateAdvancedRiskConfig(weeklyLossLimit: 10000, trailingDrawdownLimit: 5000));

            var sizer = new AdvancedPositionSizer(logger);
            var intent = CreateIntent("ES", 8, OrderSide.Buy);
            var context = CreateContext("ES", 50000, 0);
            var riskConfig = CreateRiskConfig();
            var sizingConfig = CreateSizingConfig(SizingMethod.VolatilityAdjusted, 1, 10, 500);

            // Act
            var riskDecision = advancedRiskManager.ValidateOrder(intent, context, riskConfig);
            SizingResult sizingResult = null;
            if (riskDecision.Allow)
            {
                sizingResult = sizer.CalculateSize(intent, context, sizingConfig);
            }

            // Assert
            Assert.IsTrue(riskDecision.Allow);
            Assert.IsNotNull(sizingResult);
            Assert.AreEqual(SizingMethod.VolatilityAdjusted, sizingResult.Method);
            Assert.IsTrue(sizingResult.Contracts >= sizingConfig.MinContracts);
            Assert.IsTrue(sizingResult.Contracts <= sizingConfig.MaxContracts);
        }

        /// <summary>
        /// Verifies that weekly loss limit rejection blocks order flow before sizing.
        /// </summary>
        [TestMethod]
        public void EndToEnd_WeeklyLimitBreached_RiskRejects_AndSizingIsSkipped()
        {
            // Arrange
            var logger = new BasicLogger("RiskSizingIntegrationTests");
            var basicRiskManager = new BasicRiskManager(logger);
            var advancedRiskManager = new AdvancedRiskManager(
                logger,
                basicRiskManager,
                CreateAdvancedRiskConfig(weeklyLossLimit: 3000, trailingDrawdownLimit: 50000));

            var sizer = new AdvancedPositionSizer(logger);
            var intent = CreateIntent("ES", 8, OrderSide.Buy);
            var context = CreateContext("ES", 50000, 0);
            var riskConfig = CreateRiskConfig();
            var sizingConfig = CreateSizingConfig(SizingMethod.OptimalF, 1, 10, 500);

            // Accumulate weekly losses while staying above basic emergency stop threshold.
            for (var i = 0; i < 6; i++)
            {
                advancedRiskManager.OnPnLUpdate(50000, -600);
            }

            // Act
            var riskDecision = advancedRiskManager.ValidateOrder(intent, context, riskConfig);
            SizingResult sizingResult = null;
            if (riskDecision.Allow)
            {
                sizingResult = sizer.CalculateSize(intent, context, sizingConfig);
            }

            // Assert
            Assert.IsFalse(riskDecision.Allow);
            Assert.IsTrue(riskDecision.RejectReason.Contains("Weekly loss limit breached"));
            Assert.IsNull(sizingResult);
        }

        /// <summary>
        /// Verifies that risk metrics and sizing calculations are both populated in a full pass.
        /// </summary>
        [TestMethod]
        public void EndToEnd_ApprovedFlow_ProducesRiskAndSizingDiagnostics()
        {
            // Arrange
            var logger = new BasicLogger("RiskSizingIntegrationTests");
            var basicRiskManager = new BasicRiskManager(logger);
            var advancedRiskManager = new AdvancedRiskManager(
                logger,
                basicRiskManager,
                CreateAdvancedRiskConfig(weeklyLossLimit: 10000, trailingDrawdownLimit: 5000));

            var sizer = new AdvancedPositionSizer(logger);
            var intent = CreateIntent("NQ", 10, OrderSide.Sell);
            var context = CreateContext("NQ", 60000, 250);
            var riskConfig = CreateRiskConfig();
            var sizingConfig = CreateSizingConfig(SizingMethod.KellyCriterion, 1, 12, 750);
            sizingConfig.MethodParameters.Add("kelly_fraction", 0.5);

            // Act
            var riskDecision = advancedRiskManager.ValidateOrder(intent, context, riskConfig);
            var sizingResult = sizer.CalculateSize(intent, context, sizingConfig);

            // Assert
            Assert.IsTrue(riskDecision.Allow);
            Assert.IsNotNull(riskDecision.RiskMetrics);
            Assert.IsTrue(riskDecision.RiskMetrics.ContainsKey("weekly_pnl"));
            Assert.IsTrue(riskDecision.RiskMetrics.ContainsKey("trailing_drawdown"));

            Assert.IsNotNull(sizingResult);
            Assert.IsNotNull(sizingResult.Calculations);
            Assert.IsTrue(sizingResult.Calculations.Count > 0);
            Assert.IsTrue(sizingResult.Calculations.ContainsKey("actual_risk"));
            Assert.IsTrue(sizingResult.Contracts >= sizingConfig.MinContracts);
            Assert.IsTrue(sizingResult.Contracts <= sizingConfig.MaxContracts);
        }

        private static AdvancedRiskConfig CreateAdvancedRiskConfig(double weeklyLossLimit, double trailingDrawdownLimit)
        {
            return new AdvancedRiskConfig(
                weeklyLossLimit,
                trailingDrawdownLimit,
                100000,
                TimeSpan.FromMinutes(30),
                100000,
                new List<TradingTimeWindow>());
        }

        private static RiskConfig CreateRiskConfig()
        {
            return new RiskConfig(
                dailyLossLimit: 1000,
                maxTradeRisk: 500,
                maxOpenPositions: 5,
                emergencyFlattenEnabled: true,
                weeklyLossLimit: 10000,
                trailingDrawdownLimit: 5000,
                maxCrossStrategyExposure: 100000,
                maxCorrelatedExposure: 100000);
        }

        private static SizingConfig CreateSizingConfig(SizingMethod method, int minContracts, int maxContracts, double riskPerTrade)
        {
            return new SizingConfig(
                method,
                minContracts,
                maxContracts,
                riskPerTrade,
                new Dictionary<string, object>());
        }

        private static StrategyIntent CreateIntent(string symbol, int stopTicks, OrderSide side)
        {
            return new StrategyIntent(
                symbol,
                side,
                OrderType.Market,
                null,
                stopTicks,
                2 * stopTicks,
                0.8,
                "Integration flow test intent",
                new Dictionary<string, object>());
        }

        private static StrategyContext CreateContext(string symbol, double equity, double dailyPnL)
        {
            return new StrategyContext(
                symbol,
                DateTime.UtcNow,
                new Position(symbol, 0, 0, 0, 0, DateTime.UtcNow),
                new AccountInfo(equity, equity, dailyPnL, 0, DateTime.UtcNow),
                new MarketSession(DateTime.Today.AddHours(9.5), DateTime.Today.AddHours(16), true, "RTH"),
                new Dictionary<string, object>());
        }
    }
}
