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

namespace NT8.Core.Tests.Sizing
{
    [TestClass]
    public class OptimalFCalculatorTests
    {
        [TestMethod]
        public void Constructor_NullLogger_ThrowsArgumentNullException()
        {
            // Act & Assert
            Assert.ThrowsException<ArgumentNullException>(() => new OptimalFCalculator(null));
        }

        [TestMethod]
        public void Calculate_ValidInput_ReturnsValidResult()
        {
            // Arrange
            var calculator = new OptimalFCalculator(new BasicLogger("OptimalFCalculatorTests"));
            var input = new OptimalFInput(
                tradeResults: CreateMixedTradeResults(),
                maxFLimit: 0.5,
                stepSize: 0.01,
                safetyFactor: 0.8);

            // Act
            var result = calculator.Calculate(input);

            // Assert
            Assert.IsTrue(result.IsValid);
            Assert.IsTrue(result.OptimalF > 0.0);
            Assert.IsTrue(result.OptimalF <= 0.5);
            Assert.IsTrue(result.Confidence >= 0.0);
            Assert.IsTrue(result.Confidence <= 1.0);
            Assert.AreEqual(input.TradeResults.Count, result.TradeCount);
        }

        [TestMethod]
        public void Calculate_InsufficientTrades_ThrowsArgumentException()
        {
            // Arrange
            var calculator = new OptimalFCalculator(new BasicLogger("OptimalFCalculatorTests"));
            var trades = new List<double>();
            trades.Add(100);
            trades.Add(-50);
            trades.Add(80);
            trades.Add(-40);
            trades.Add(60);

            var input = new OptimalFInput(
                tradeResults: trades,
                maxFLimit: 1.0,
                stepSize: 0.01,
                safetyFactor: 1.0);

            // Act & Assert
            Assert.ThrowsException<ArgumentException>(() => calculator.Calculate(input));
        }

        [TestMethod]
        public void Calculate_AllZeroTrades_ThrowsArgumentException()
        {
            // Arrange
            var calculator = new OptimalFCalculator(new BasicLogger("OptimalFCalculatorTests"));
            var trades = new List<double>();
            for (var i = 0; i < 12; i++)
            {
                trades.Add(0.0);
            }

            var input = new OptimalFInput(
                tradeResults: trades,
                maxFLimit: 1.0,
                stepSize: 0.01,
                safetyFactor: 1.0);

            // Act & Assert
            Assert.ThrowsException<ArgumentException>(() => calculator.Calculate(input));
        }

        [TestMethod]
        public void CalculateKellyFraction_ValidTrades_ReturnsBoundedValue()
        {
            // Arrange
            var calculator = new OptimalFCalculator(new BasicLogger("OptimalFCalculatorTests"));
            var trades = CreateMixedTradeResults();

            // Act
            var kelly = calculator.CalculateKellyFraction(trades);

            // Assert
            Assert.IsTrue(kelly >= 0.01);
            Assert.IsTrue(kelly <= 0.5);
        }

        [TestMethod]
        public void GeneratePerformanceCurve_ValidInput_ReturnsCurvePoints()
        {
            // Arrange
            var calculator = new OptimalFCalculator(new BasicLogger("OptimalFCalculatorTests"));
            var trades = CreateMixedTradeResults();

            // Act
            var curve = calculator.GeneratePerformanceCurve(trades, 0.05);

            // Assert
            Assert.IsNotNull(curve);
            Assert.IsTrue(curve.Count > 0);
        }

        private static List<double> CreateMixedTradeResults()
        {
            var trades = new List<double>();

            trades.Add(120);
            trades.Add(-60);
            trades.Add(95);
            trades.Add(-45);
            trades.Add(70);
            trades.Add(-30);
            trades.Add(140);
            trades.Add(-80);
            trades.Add(65);
            trades.Add(-35);
            trades.Add(110);
            trades.Add(-50);

            return trades;
        }
    }
}
