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

namespace NT8.Integration.Tests
{
    /// <summary>
    /// Integration tests for Phase 4 intelligence flow.
    /// </summary>
    [TestClass]
    public class Phase4IntegrationTests
    {
        [TestMethod]
        public void FullFlow_ConfluenceToGradeFilter_AllowsTradeInPCP()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var scorer = new ConfluenceScorer(logger, 100);
            var filter = new GradeFilter();
            var modeManager = new RiskModeManager(logger);

            var intent = CreateIntent(OrderSide.Buy);
            var context = CreateContext();
            var bar = CreateBar();
            var factors = CreateStrongFactors();

            var score = scorer.CalculateScore(intent, context, bar, factors);
            var mode = modeManager.GetCurrentMode();
            var allowed = filter.ShouldAcceptTrade(score.Grade, mode);

            Assert.IsTrue(allowed);
            Assert.IsTrue(score.WeightedScore >= 0.70);
        }

        [TestMethod]
        public void FullFlow_LowConfluence_RejectedInPCP()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var scorer = new ConfluenceScorer(logger, 100);
            var filter = new GradeFilter();

            var intent = CreateIntent(OrderSide.Buy);
            var context = CreateContext();
            var bar = CreateBar();
            var factors = CreateWeakFactors();

            var score = scorer.CalculateScore(intent, context, bar, factors);
            var allowed = filter.ShouldAcceptTrade(score.Grade, RiskMode.PCP);

            Assert.IsFalse(allowed);
            Assert.AreEqual(TradeGrade.F, score.Grade);
        }

        [TestMethod]
        public void FullFlow_ModeTransitionToHR_BlocksTrades()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var modeManager = new RiskModeManager(logger);
            var filter = new GradeFilter();

            modeManager.UpdateRiskMode(-500.0, 0, 3);
            var mode = modeManager.GetCurrentMode();

            var allowed = filter.ShouldAcceptTrade(TradeGrade.APlus, mode);
            Assert.AreEqual(RiskMode.HR, mode);
            Assert.IsFalse(allowed);
        }

        [TestMethod]
        public void FullFlow_GradeBasedSizer_AppliesGradeAndModeMultipliers()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var filter = new GradeFilter();
            var gradeSizer = new GradeBasedSizer(logger, filter);

            var baseSizer = new StubSizer(4, 400.0);
            var intent = CreateIntent(OrderSide.Buy);
            var context = CreateContext();
            var confluence = CreateScore(TradeGrade.A, 0.85);
            var config = new SizingConfig(SizingMethod.FixedDollarRisk, 1, 20, 500.0, new Dictionary<string, object>());
            var modeConfig = new RiskModeConfig(RiskMode.ECP, 1.5, TradeGrade.B, 1500.0, 4, true, new Dictionary<string, object>());

            var result = gradeSizer.CalculateGradeBasedSize(
                intent,
                context,
                confluence,
                RiskMode.ECP,
                config,
                baseSizer,
                modeConfig);

            // 4 * 1.25 * 1.5 = 7.5 => 7
            Assert.AreEqual(7, result.Contracts);
            Assert.IsTrue(result.Calculations.ContainsKey("combined_multiplier"));
        }

        [TestMethod]
        public void FullFlow_RegimeManager_ShouldAdjustForExtremeVolatility()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var vol = new VolatilityRegimeDetector(logger, 20);
            var trend = new TrendRegimeDetector(logger);
            var regimeManager = new RegimeManager(logger, vol, trend, 50, 50);

            var bars = BuildUptrendBars(6, 5000.0, 1.0);
            for (var i = 0; i < bars.Count; i++)
            {
                regimeManager.UpdateRegime("ES", bars[i], 5000.0, 2.4, 1.0);
            }

            var shouldAdjust = regimeManager.ShouldAdjustStrategy("ES", CreateIntent(OrderSide.Buy));
            Assert.IsTrue(shouldAdjust);
        }

        [TestMethod]
        public void FullFlow_ConfluenceStatsAndModeState_AreAvailable()
        {
            var logger = new BasicLogger("Phase4IntegrationTests");
            var scorer = new ConfluenceScorer(logger, 10);
            var modeManager = new RiskModeManager(logger);

            var score = scorer.CalculateScore(CreateIntent(OrderSide.Buy), CreateContext(), CreateBar(), CreateStrongFactors());
            var stats = scorer.GetHistoricalStats();
            var state = modeManager.GetState();

            Assert.IsNotNull(score);
            Assert.IsNotNull(stats);
            Assert.IsNotNull(state);
            Assert.IsTrue(stats.TotalCalculations >= 1);
        }

        private static StrategyIntent CreateIntent(OrderSide side)
        {
            return new StrategyIntent(
                "ES",
                side,
                OrderType.Market,
                null,
                8,
                16,
                0.8,
                "Phase4 integration",
                new Dictionary<string, object>());
        }

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

        private static BarData CreateBar()
        {
            return new BarData("ES", DateTime.UtcNow, 5000, 5004, 4998, 5003, 1200, TimeSpan.FromMinutes(1));
        }

        private static ConfluenceScore CreateScore(TradeGrade grade, double weighted)
        {
            var factors = new List<ConfluenceFactor>();
            factors.Add(new ConfluenceFactor(FactorType.Setup, "Setup", weighted, 1.0, "test", new Dictionary<string, object>()));
            return new ConfluenceScore(weighted, weighted, grade, factors, DateTime.UtcNow, new Dictionary<string, object>());
        }

        private static List<IFactorCalculator> CreateStrongFactors()
        {
            var factors = new List<IFactorCalculator>();
            factors.Add(new FixedFactor(FactorType.Setup, 0.90));
            factors.Add(new FixedFactor(FactorType.Trend, 0.85));
            factors.Add(new FixedFactor(FactorType.Volatility, 0.80));
            return factors;
        }

        private static List<IFactorCalculator> CreateWeakFactors()
        {
            var factors = new List<IFactorCalculator>();
            factors.Add(new FixedFactor(FactorType.Setup, 0.20));
            factors.Add(new FixedFactor(FactorType.Trend, 0.30));
            factors.Add(new FixedFactor(FactorType.Volatility, 0.25));
            return factors;
        }

        private static List<BarData> BuildUptrendBars(int count, double start, double step)
        {
            var list = new List<BarData>();
            var t = DateTime.UtcNow.AddMinutes(-count);
            for (var i = 0; i < count; i++)
            {
                var close = start + (i * step);
                list.Add(new BarData("ES", t.AddMinutes(i), close - 1.0, close + 1.0, close - 2.0, close, 1000 + i, TimeSpan.FromMinutes(1)));
            }
            return list;
        }

        private class FixedFactor : IFactorCalculator
        {
            private readonly FactorType _type;
            private readonly double _score;

            public FixedFactor(FactorType type, double score)
            {
                _type = type;
                _score = score;
            }

            public FactorType Type
            {
                get { return _type; }
            }

            public ConfluenceFactor Calculate(StrategyIntent intent, StrategyContext context, BarData bar)
            {
                return new ConfluenceFactor(_type, "Fixed", _score, 1.0, "fixed", new Dictionary<string, object>());
            }
        }

        private class StubSizer : IPositionSizer
        {
            private readonly int _contracts;
            private readonly double _risk;

            public StubSizer(int contracts, double risk)
            {
                _contracts = contracts;
                _risk = risk;
            }

            public SizingResult CalculateSize(StrategyIntent intent, StrategyContext context, SizingConfig config)
            {
                return new SizingResult(_contracts, _risk, SizingMethod.FixedDollarRisk, new Dictionary<string, object>());
            }

            public SizingMetadata GetMetadata()
            {
                return new SizingMetadata("Stub", "Stub", new List<string>());
            }
        }
    }
}
