using Microsoft.VisualStudio.TestTools.UnitTesting;
using NT8.Adapters.Wrappers;
using NT8.Core.Common.Interfaces;
using NT8.Core.Common.Models;
using NT8.Core.Logging;
using System;
using System.Collections.Generic;

namespace NT8.Integration.Tests
{
    /// <summary>
    /// Integration tests for NT8 strategy wrapper behavior.
    /// </summary>
    [TestClass]
    public class NT8WrapperTests
    {
        /// <summary>
        /// Verifies wrapper construction initializes expected defaults.
        /// </summary>
        [TestMethod]
        public void Constructor_Defaults_AreInitialized()
        {
            // Arrange / Act
            var wrapper = new SimpleORBNT8Wrapper();

            // Assert
            Assert.AreEqual(10, wrapper.StopTicks);
            Assert.AreEqual(20, wrapper.TargetTicks);
            Assert.AreEqual(100.0, wrapper.RiskAmount);
            Assert.AreEqual(30, wrapper.OpeningRangeMinutes);
            Assert.AreEqual(1.0, wrapper.StdDevMultiplier);
        }

        /// <summary>
        /// Verifies processing a valid bar/context does not throw when strategy emits no intent.
        /// </summary>
        [TestMethod]
        public void ProcessBarUpdate_ValidData_NoIntent_DoesNotThrow()
        {
            // Arrange
            var wrapper = new SimpleORBNT8Wrapper();
            var bar = CreateBar("ES");
            var context = CreateContext("ES");

            // Act
            wrapper.ProcessBarUpdate(bar, context);

            // Assert
            Assert.IsTrue(true);
        }

        /// <summary>
        /// Verifies null bar input is rejected.
        /// </summary>
        [TestMethod]
        public void ProcessBarUpdate_NullBar_ThrowsArgumentNullException()
        {
            // Arrange
            var wrapper = new SimpleORBNT8Wrapper();
            var context = CreateContext("NQ");

            // Act / Assert
            Assert.ThrowsException<ArgumentNullException>(
                () => wrapper.ProcessBarUpdate(null, context));
        }

        /// <summary>
        /// Verifies null context input is rejected.
        /// </summary>
        [TestMethod]
        public void ProcessBarUpdate_NullContext_ThrowsArgumentNullException()
        {
            // Arrange
            var wrapper = new SimpleORBNT8Wrapper();
            var bar = CreateBar("NQ");

            // Act / Assert
            Assert.ThrowsException<ArgumentNullException>(
                () => wrapper.ProcessBarUpdate(bar, null));
        }

        /// <summary>
        /// Verifies wrapper can process a generated intent flow from a derived test strategy.
        /// </summary>
        [TestMethod]
        public void ProcessBarUpdate_WithGeneratedIntent_CompletesWithoutException()
        {
            // Arrange
            var wrapper = new TestIntentWrapper();
            var bar = CreateBar("MES");
            var context = CreateContext("MES");

            // Act
            wrapper.ProcessBarUpdate(bar, context);

            // Assert
            Assert.IsTrue(true);
        }

        /// <summary>
        /// Verifies Simple ORB strategy emits a long intent after opening range breakout.
        /// </summary>
        [TestMethod]
        public void ProcessBarUpdate_SimpleOrbBreakout_ProducesExecutionRecord()
        {
            // Arrange
            var wrapper = new SimpleORBNT8Wrapper();
            var sessionStart = DateTime.Today.AddHours(9.5);
            var symbol = "ES";

            var openingBar1 = new BarData(symbol, sessionStart.AddMinutes(5), 100, 101, 99, 100.5, 1000, TimeSpan.FromMinutes(5));
            var openingBar2 = new BarData(symbol, sessionStart.AddMinutes(10), 100.5, 102, 100, 101.5, 1000, TimeSpan.FromMinutes(5));
            var breakoutBar = new BarData(symbol, sessionStart.AddMinutes(35), 102, 104.5, 101.5, 104.2, 1200, TimeSpan.FromMinutes(5));

            // Act
            wrapper.ProcessBarUpdate(openingBar1, CreateContext(symbol, openingBar1.Time, sessionStart));
            wrapper.ProcessBarUpdate(openingBar2, CreateContext(symbol, openingBar2.Time, sessionStart));
            wrapper.ProcessBarUpdate(breakoutBar, CreateContext(symbol, breakoutBar.Time, sessionStart));

            // Assert
            var adapter = wrapper.GetAdapterForTesting();
            var records = adapter.GetExecutionHistory();
            Assert.AreEqual(1, records.Count);
            Assert.AreEqual(OrderSide.Buy, records[0].Side);
            Assert.AreEqual(symbol, records[0].Symbol);
        }

        private static BarData CreateBar(string symbol)
        {
            return new BarData(
                symbol,
                DateTime.UtcNow,
                5000,
                5010,
                4995,
                5005,
                10000,
                TimeSpan.FromMinutes(5));
        }

        private static StrategyContext CreateContext(string symbol)
        {
            return new StrategyContext(
                symbol,
                DateTime.UtcNow,
                new Position(symbol, 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 StrategyContext CreateContext(string symbol, DateTime currentTime, DateTime sessionStart)
        {
            return new StrategyContext(
                symbol,
                currentTime,
                new Position(symbol, 0, 0, 0, 0, currentTime),
                new AccountInfo(100000, 100000, 0, 0, currentTime),
                new MarketSession(sessionStart, sessionStart.AddHours(6.5), true, "RTH"),
                new Dictionary<string, object>());
        }

        /// <summary>
        /// Wrapper used to verify execution path when an intent is emitted.
        /// </summary>
        private class TestIntentWrapper : BaseNT8StrategyWrapper
        {
            protected override IStrategy CreateSdkStrategy()
            {
                return new TestIntentStrategy();
            }
        }

        /// <summary>
        /// Minimal strategy that always returns a valid intent.
        /// </summary>
        private class TestIntentStrategy : IStrategy
        {
            public StrategyMetadata Metadata { get; private set; }

            public TestIntentStrategy()
            {
                Metadata = new StrategyMetadata(
                    "TestIntentStrategy",
                    "Test strategy that emits a deterministic intent",
                    "1.0",
                    "NT8 SDK Tests",
                    new string[] { "MES" },
                    1);
            }

            public void Initialize(StrategyConfig config, IMarketDataProvider dataProvider, ILogger logger)
            {
                // No-op for test strategy.
            }

            public StrategyIntent OnBar(BarData bar, StrategyContext context)
            {
                return new StrategyIntent(
                    context.Symbol,
                    OrderSide.Buy,
                    OrderType.Market,
                    null,
                    8,
                    16,
                    0.7,
                    "Wrapper integration test intent",
                    new Dictionary<string, object>());
            }

            public StrategyIntent OnTick(TickData tick, StrategyContext context)
            {
                return null;
            }

            public Dictionary<string, object> GetParameters()
            {
                return new Dictionary<string, object>();
            }

            public void SetParameters(Dictionary<string, object> parameters)
            {
                // No-op for test strategy.
            }
        }
    }
}
