using Microsoft.VisualStudio.TestTools.UnitTesting;
using NT8.Adapters.NinjaTrader;
using NT8.Core.Common.Models;
using NT8.Core.Risk;
using NT8.Core.Sizing;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace NT8.Integration.Tests
{
    /// <summary>
    /// Integration tests for NT8OrderAdapter behavior.
    /// </summary>
    [TestClass]
    public class NT8OrderAdapterIntegrationTests
    {
        [TestMethod]
        public void Initialize_NullRiskManager_ThrowsArgumentNullException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();
            var sizer = new TestPositionSizer(1);

            // Act / Assert
            Assert.ThrowsException<ArgumentNullException>(
                () => adapter.Initialize(null, sizer));
        }

        [TestMethod]
        public void Initialize_NullPositionSizer_ThrowsArgumentNullException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();
            var risk = new TestRiskManager(true);

            // Act / Assert
            Assert.ThrowsException<ArgumentNullException>(
                () => adapter.Initialize(risk, null));
        }

        [TestMethod]
        public void ExecuteIntent_NotInitialized_ThrowsInvalidOperationException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();

            // Act / Assert
            Assert.ThrowsException<InvalidOperationException>(
                () => adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig()));
        }

        [TestMethod]
        public void ExecuteIntent_RiskRejected_DoesNotRecordExecution()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();
            var risk = new TestRiskManager(false);
            var sizer = new TestPositionSizer(3);
            adapter.Initialize(risk, sizer);

            // Act
            adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig());
            var history = adapter.GetExecutionHistory();

            // Assert
            Assert.AreEqual(0, history.Count);
        }

        [TestMethod]
        public void ExecuteIntent_AllowedAndSized_RecordsExecution()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();
            var risk = new TestRiskManager(true);
            var sizer = new TestPositionSizer(4);
            adapter.Initialize(risk, sizer);

            // Act
            adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig());
            var history = adapter.GetExecutionHistory();

            // Assert
            Assert.AreEqual(1, history.Count);
            Assert.AreEqual("ES", history[0].Symbol);
            Assert.AreEqual(OrderSide.Buy, history[0].Side);
            Assert.AreEqual(OrderType.Market, history[0].EntryType);
            Assert.AreEqual(4, history[0].Contracts);
            Assert.AreEqual(8, history[0].StopTicks);
            Assert.AreEqual(16, history[0].TargetTicks);
        }

        [TestMethod]
        public void GetExecutionHistory_ReturnsCopy_NotMutableInternalReference()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();
            var risk = new TestRiskManager(true);
            var sizer = new TestPositionSizer(2);
            adapter.Initialize(risk, sizer);
            adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig());

            // Act
            var history = adapter.GetExecutionHistory();
            history.Clear();
            var historyAfterClear = adapter.GetExecutionHistory();

            // Assert
            Assert.AreEqual(1, historyAfterClear.Count);
        }

        [TestMethod]
        public void OnOrderUpdate_EmptyOrderId_ThrowsArgumentException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();

            // Act / Assert
            Assert.ThrowsException<ArgumentException>(
                () => adapter.OnOrderUpdate("", 0, 0, 1, 0, 0, "Working", DateTime.UtcNow, "", ""));
        }

        [TestMethod]
        public void OnExecutionUpdate_EmptyExecutionId_ThrowsArgumentException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();

            // Act / Assert
            Assert.ThrowsException<ArgumentException>(
                () => adapter.OnExecutionUpdate("", "O1", 100, 1, "Long", DateTime.UtcNow));
        }

        [TestMethod]
        public void OnExecutionUpdate_EmptyOrderId_ThrowsArgumentException()
        {
            // Arrange
            var adapter = new NT8OrderAdapter();

            // Act / Assert
            Assert.ThrowsException<ArgumentException>(
                () => adapter.OnExecutionUpdate("E1", "", 100, 1, "Long", DateTime.UtcNow));
        }

        private static StrategyIntent CreateIntent()
        {
            return new StrategyIntent(
                "ES",
                OrderSide.Buy,
                OrderType.Market,
                null,
                8,
                16,
                0.8,
                "Order adapter integration test",
                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 StrategyConfig CreateConfig()
        {
            return new StrategyConfig(
                "Test",
                "ES",
                new Dictionary<string, object>(),
                new RiskConfig(1000, 500, 5, true),
                new SizingConfig(SizingMethod.FixedContracts, 1, 10, 500, new Dictionary<string, object>()));
        }

        /// <summary>
        /// Test risk manager implementation for adapter tests.
        /// </summary>
        private class TestRiskManager : IRiskManager
        {
            private readonly bool _allow;

            public TestRiskManager(bool allow)
            {
                _allow = allow;
            }

            public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context, RiskConfig config)
            {
                return new RiskDecision(
                    _allow,
                    _allow ? null : "Rejected by test risk manager",
                    intent,
                    RiskLevel.Low,
                    new Dictionary<string, object>());
            }

            public void OnFill(OrderFill fill)
            {
            }

            public void OnPnLUpdate(double netPnL, double dayPnL)
            {
            }

            public Task<bool> EmergencyFlatten(string reason)
            {
                return Task.FromResult(true);
            }

            public RiskStatus GetRiskStatus()
            {
                return new RiskStatus(true, 0, 1000, 0, 0, DateTime.UtcNow, new List<string>());
            }
        }

        /// <summary>
        /// Test position sizer implementation for adapter tests.
        /// </summary>
        private class TestPositionSizer : IPositionSizer
        {
            private readonly int _contracts;

            public TestPositionSizer(int contracts)
            {
                _contracts = contracts;
            }

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

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