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

namespace NT8.Core.Tests.Sizing
{
    [TestClass]
    public class VolatilityAdjustedSizerTests
    {
        [TestMethod]
        public void Constructor_NullLogger_ThrowsArgumentNullException()
        {
            Assert.ThrowsException<ArgumentNullException>(() => new VolatilityAdjustedSizer(null));
        }

        [TestMethod]
        public void CalculateAdjustedSize_HigherVolatility_ReducesContracts()
        {
            var sizer = new VolatilityAdjustedSizer(new BasicLogger("VolatilityAdjustedSizerTests"));
            var constraints = ContractConstraints.CreateDefault();
            var metrics = new VolatilityMetrics(
                atr: 4.0,
                standardDeviation: 0.0,
                regime: VolatilityRegime.High,
                historicalVolatility: 0.0,
                volatilityPercentile: 75.0,
                periods: 20,
                timestamp: DateTime.UtcNow,
                isValid: true);

            var contracts = sizer.CalculateAdjustedSize(
                baseContracts: 10,
                volatilityMetrics: metrics,
                targetVolatility: 2.0,
                method: VolatilityRegime.Normal,
                constraints: constraints);

            Assert.IsTrue(contracts < 10);
        }

        [TestMethod]
        public void CalculateAdjustedSize_LowerVolatility_IncreasesContracts()
        {
            var sizer = new VolatilityAdjustedSizer(new BasicLogger("VolatilityAdjustedSizerTests"));
            var constraints = new ContractConstraints(
                minContracts: 1,
                maxContracts: 200,
                lotSize: 1,
                roundingMode: RoundingMode.Floor,
                enforceLotSize: false,
                maxPositionValue: null);

            var metrics = new VolatilityMetrics(
                atr: 1.0,
                standardDeviation: 0.0,
                regime: VolatilityRegime.Low,
                historicalVolatility: 0.0,
                volatilityPercentile: 25.0,
                periods: 20,
                timestamp: DateTime.UtcNow,
                isValid: true);

            var contracts = sizer.CalculateAdjustedSize(
                baseContracts: 10,
                volatilityMetrics: metrics,
                targetVolatility: 2.0,
                method: VolatilityRegime.Normal,
                constraints: constraints);

            Assert.IsTrue(contracts > 10);
        }

        [TestMethod]
        public void CalculateRegimeBasedSize_ExtremeRegime_ReducesContracts()
        {
            var sizer = new VolatilityAdjustedSizer(new BasicLogger("VolatilityAdjustedSizerTests"));
            var constraints = ContractConstraints.CreateDefault();

            var contracts = sizer.CalculateRegimeBasedSize(
                baseContracts: 20,
                regime: VolatilityRegime.Extreme,
                constraints: constraints);

            Assert.IsTrue(contracts <= 5);
        }

        [TestMethod]
        public void CalculateRegimeBasedSize_VeryLowRegime_IncreasesContracts()
        {
            var sizer = new VolatilityAdjustedSizer(new BasicLogger("VolatilityAdjustedSizerTests"));
            var constraints = new ContractConstraints(
                minContracts: 1,
                maxContracts: 200,
                lotSize: 1,
                roundingMode: RoundingMode.Floor,
                enforceLotSize: false,
                maxPositionValue: null);

            var contracts = sizer.CalculateRegimeBasedSize(
                baseContracts: 10,
                regime: VolatilityRegime.VeryLow,
                constraints: constraints);

            Assert.IsTrue(contracts >= 14);
        }

        [TestMethod]
        public void CalculateAdjustedSize_InvalidBaseContracts_ThrowsArgumentException()
        {
            var sizer = new VolatilityAdjustedSizer(new BasicLogger("VolatilityAdjustedSizerTests"));
            var constraints = ContractConstraints.CreateDefault();
            var metrics = VolatilityMetrics.CreateInvalid();

            Assert.ThrowsException<ArgumentException>(() =>
                sizer.CalculateAdjustedSize(0, metrics, 1.0, VolatilityRegime.Normal, constraints));
        }
    }
}
