using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NT8.Core.OMS;
using NT8.Core.Tests.Mocks;

namespace NT8.Core.Tests.OMS
{
    [TestClass]
    public class OrderTypeValidatorTests
    {
        private OrderTypeValidator _validator;

        [TestInitialize]
        public void Setup()
        {
            _validator = new OrderTypeValidator(new MockLogger<OrderTypeValidator>());
        }

        [TestMethod]
        public void Constructor_NullLogger_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                new OrderTypeValidator(null);
            });
        }

        [TestMethod]
        public void ValidateLimitOrder_ValidBuy_ReturnsValid()
        {
            var request = new LimitOrderRequest("ES", OrderSide.Buy, 1, 5000m, TimeInForce.Day);
            var result = _validator.ValidateLimitOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateLimitOrder_ValidSell_ReturnsValid()
        {
            var request = new LimitOrderRequest("ES", OrderSide.Sell, 1, 5002m, TimeInForce.Day);
            var result = _validator.ValidateLimitOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateLimitOrder_InvalidQuantity_ReturnsInvalid()
        {
            var request = new LimitOrderRequest("ES", OrderSide.Buy, 1, 5000m, TimeInForce.Day);
            request.Quantity = 0;
            var result = _validator.ValidateLimitOrder(request, 5001m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateLimitOrder_NullRequest_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                _validator.ValidateLimitOrder(null, 1m);
            });
        }

        [TestMethod]
        public void ValidateStopOrder_BuyStopAboveMarket_ReturnsValid()
        {
            var request = new StopOrderRequest("NQ", OrderSide.Buy, 1, 18001m, TimeInForce.Day);
            var result = _validator.ValidateStopOrder(request, 18000m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopOrder_BuyStopBelowMarket_ReturnsInvalid()
        {
            var request = new StopOrderRequest("NQ", OrderSide.Buy, 1, 17999m, TimeInForce.Day);
            var result = _validator.ValidateStopOrder(request, 18000m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopOrder_SellStopBelowMarket_ReturnsValid()
        {
            var request = new StopOrderRequest("NQ", OrderSide.Sell, 1, 17999m, TimeInForce.Day);
            var result = _validator.ValidateStopOrder(request, 18000m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopOrder_SellStopAboveMarket_ReturnsInvalid()
        {
            var request = new StopOrderRequest("NQ", OrderSide.Sell, 1, 18001m, TimeInForce.Day);
            var result = _validator.ValidateStopOrder(request, 18000m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopOrder_NullRequest_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                _validator.ValidateStopOrder(null, 1m);
            });
        }

        [TestMethod]
        public void ValidateStopLimitOrder_BuyValidRelationship_ReturnsValid()
        {
            var request = new StopLimitOrderRequest("CL", OrderSide.Buy, 1, 81m, 81.1m, TimeInForce.Day);
            var result = _validator.ValidateStopLimitOrder(request, 80m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopLimitOrder_BuyInvalidLimitBelowStop_ReturnsInvalid()
        {
            var request = new StopLimitOrderRequest("CL", OrderSide.Buy, 1, 81m, 80.9m, TimeInForce.Day);
            var result = _validator.ValidateStopLimitOrder(request, 80m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopLimitOrder_SellValidRelationship_ReturnsValid()
        {
            var request = new StopLimitOrderRequest("CL", OrderSide.Sell, 1, 79m, 78.9m, TimeInForce.Day);
            var result = _validator.ValidateStopLimitOrder(request, 80m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopLimitOrder_SellInvalidLimitAboveStop_ReturnsInvalid()
        {
            var request = new StopLimitOrderRequest("CL", OrderSide.Sell, 1, 79m, 79.1m, TimeInForce.Day);
            var result = _validator.ValidateStopLimitOrder(request, 80m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateStopLimitOrder_NullRequest_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                _validator.ValidateStopLimitOrder(null, 1m);
            });
        }

        [TestMethod]
        public void ValidateMITOrder_BuyTriggerBelowMarket_ReturnsValid()
        {
            var request = new MITOrderRequest("GC", OrderSide.Buy, 1, 1999m, TimeInForce.Day);
            var result = _validator.ValidateMITOrder(request, 2000m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateMITOrder_BuyTriggerAboveMarket_ReturnsInvalid()
        {
            var request = new MITOrderRequest("GC", OrderSide.Buy, 1, 2001m, TimeInForce.Day);
            var result = _validator.ValidateMITOrder(request, 2000m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateMITOrder_SellTriggerAboveMarket_ReturnsValid()
        {
            var request = new MITOrderRequest("GC", OrderSide.Sell, 1, 2001m, TimeInForce.Day);
            var result = _validator.ValidateMITOrder(request, 2000m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateMITOrder_SellTriggerBelowMarket_ReturnsInvalid()
        {
            var request = new MITOrderRequest("GC", OrderSide.Sell, 1, 1999m, TimeInForce.Day);
            var result = _validator.ValidateMITOrder(request, 2000m);
            Assert.IsFalse(result.IsValid);
        }

        [TestMethod]
        public void ValidateMITOrder_NullRequest_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                _validator.ValidateMITOrder(null, 1m);
            });
        }

        [TestMethod]
        public void ValidateOrder_LimitOrder_DispatchesCorrectly()
        {
            var request = new LimitOrderRequest("ES", OrderSide.Buy, 1, 5000m, TimeInForce.Day);
            var result = _validator.ValidateOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateOrder_StopOrder_DispatchesCorrectly()
        {
            var request = new StopOrderRequest("ES", OrderSide.Buy, 1, 5002m, TimeInForce.Day);
            var result = _validator.ValidateOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateOrder_StopLimitOrder_DispatchesCorrectly()
        {
            var request = new StopLimitOrderRequest("ES", OrderSide.Buy, 1, 5002m, 5002.25m, TimeInForce.Day);
            var result = _validator.ValidateOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateOrder_MitOrder_DispatchesCorrectly()
        {
            var request = new MITOrderRequest("ES", OrderSide.Buy, 1, 5000m, TimeInForce.Day);
            var result = _validator.ValidateOrder(request, 5001m);
            Assert.IsTrue(result.IsValid);
        }

        [TestMethod]
        public void ValidateOrder_NullRequest_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(delegate
            {
                _validator.ValidateOrder(null, 1m);
            });
        }
    }
}
