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

namespace NT8.Core.Tests.Sizing
{
    [TestClass]
    public class AdvancedPositionSizerTests
    {
        private AdvancedPositionSizer _sizer;

        [TestInitialize]
        public void TestInitialize()
        {
            _sizer = new AdvancedPositionSizer(new BasicLogger("AdvancedPositionSizerTests"));
        }

        [TestMethod]
        public void CalculateSize_OptimalF_NoHistory_UsesFallbackMethod()
        {
            // Arrange
            var intent = CreateValidIntent();
            var context = CreateContext();
            var config = CreateConfig(SizingMethod.OptimalF);

            // Act
            var result = _sizer.CalculateSize(intent, context, config);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(SizingMethod.FixedDollarRisk, result.Method);
            Assert.IsTrue(result.Contracts >= config.MinContracts);
            Assert.IsTrue(result.Contracts <= config.MaxContracts);
        }

        [TestMethod]
        public void CalculateSize_KellyCriterion_WithFraction_ReturnsValidContracts()
        {
            // Arrange
            var intent = CreateValidIntent();
            var context = CreateContext();
            var config = CreateConfig(SizingMethod.KellyCriterion);
            config.MethodParameters.Add("kelly_fraction", 0.5);

            // Act
            var result = _sizer.CalculateSize(intent, context, config);

            // Assert
            Assert.IsNotNull(result);
            Assert.IsTrue(result.Contracts >= config.MinContracts);
            Assert.IsTrue(result.Contracts <= config.MaxContracts);
            Assert.IsTrue(result.RiskAmount >= 0);
        }

        [TestMethod]
        public void CalculateSize_VolatilityAdjusted_ReturnsValidContracts()
        {
            // Arrange
            var intent = CreateValidIntent(symbol: "NQ", stopTicks: 10);
            var context = CreateContext(symbol: "NQ");
            var config = CreateConfig(SizingMethod.VolatilityAdjusted);

            // Act
            var result = _sizer.CalculateSize(intent, context, config);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(SizingMethod.VolatilityAdjusted, result.Method);
            Assert.IsTrue(result.Contracts >= config.MinContracts);
            Assert.IsTrue(result.Contracts <= config.MaxContracts);
        }

        [TestMethod]
        public void CalculateSize_InvalidIntent_ReturnsZeroContracts()
        {
            // Arrange
            var invalidIntent = new StrategyIntent(
                symbol: "ES",
                side: OrderSide.Flat,
                entryType: OrderType.Market,
                limitPrice: null,
                stopTicks: 0,
                targetTicks: null,
                confidence: 0.8,
                reason: "Invalid for test",
                metadata: new Dictionary<string, object>());

            var context = CreateContext();
            var config = CreateConfig(SizingMethod.OptimalF);

            // Act
            var result = _sizer.CalculateSize(invalidIntent, context, config);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(0, result.Contracts);
        }

        [TestMethod]
        public void ValidateConfig_InvalidValues_ReturnsFalseAndErrors()
        {
            // Arrange
            var config = new SizingConfig(
                method: SizingMethod.KellyCriterion,
                minContracts: 5,
                maxContracts: 1,
                riskPerTrade: -1,
                methodParameters: new Dictionary<string, object>());

            // Act
            List<string> errors;
            var isValid = AdvancedPositionSizer.ValidateConfig(config, out errors);

            // Assert
            Assert.IsFalse(isValid);
            Assert.IsNotNull(errors);
            Assert.IsTrue(errors.Count > 0);
        }

        [TestMethod]
        public void GetMetadata_ReturnsExpectedFields()
        {
            // Act
            var metadata = _sizer.GetMetadata();

            // Assert
            Assert.IsNotNull(metadata);
            Assert.AreEqual("Advanced Position Sizer", metadata.Name);
            Assert.IsTrue(metadata.RequiredParameters.Contains("method"));
            Assert.IsTrue(metadata.RequiredParameters.Contains("risk_per_trade"));
        }

        private static StrategyIntent CreateValidIntent(string symbol = "ES", int stopTicks = 8)
        {
            return new StrategyIntent(
                symbol: symbol,
                side: OrderSide.Buy,
                entryType: OrderType.Market,
                limitPrice: null,
                stopTicks: stopTicks,
                targetTicks: 16,
                confidence: 0.8,
                reason: "Test intent",
                metadata: new Dictionary<string, object>());
        }

        private static StrategyContext CreateContext(string symbol = "ES")
        {
            return new StrategyContext(
                symbol: symbol,
                currentTime: DateTime.UtcNow,
                currentPosition: new Position(symbol, 0, 0, 0, 0, DateTime.UtcNow),
                account: new AccountInfo(50000, 50000, 0, 0, DateTime.UtcNow),
                session: new MarketSession(DateTime.Today.AddHours(9.5), DateTime.Today.AddHours(16), true, "RTH"),
                customData: new Dictionary<string, object>());
        }

        private static SizingConfig CreateConfig(SizingMethod method)
        {
            return new SizingConfig(
                method: method,
                minContracts: 1,
                maxContracts: 10,
                riskPerTrade: 500,
                methodParameters: new Dictionary<string, object>());
        }
    }
}
