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 BasicPositionSizerTests
    {
        private BasicPositionSizer _sizer;

        [TestInitialize]
        public void TestInitialize()
        {
            _sizer = new BasicPositionSizer(new BasicLogger("BasicPositionSizerTests"));
        }

        [TestMethod]
        public void CalculateSize_FixedContracts_ReturnsConfiguredContractsWithinBounds()
        {
            var intent = CreateIntent(stopTicks: 8);
            var context = CreateContext();

            var parameters = new Dictionary<string, object>();
            parameters.Add("contracts", 3);

            var config = new SizingConfig(
                method: SizingMethod.FixedContracts,
                minContracts: 1,
                maxContracts: 10,
                riskPerTrade: 500,
                methodParameters: parameters);

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

            Assert.AreEqual(3, result.Contracts);
            Assert.AreEqual(SizingMethod.FixedContracts, result.Method);
            Assert.IsTrue(result.RiskAmount > 0);
        }

        [TestMethod]
        public void CalculateSize_FixedDollarRisk_ReturnsContractsWithinBounds()
        {
            var intent = CreateIntent(stopTicks: 8);
            var context = CreateContext();
            var config = new SizingConfig(
                method: SizingMethod.FixedDollarRisk,
                minContracts: 1,
                maxContracts: 10,
                riskPerTrade: 500,
                methodParameters: new Dictionary<string, object>());

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

            Assert.IsTrue(result.Contracts >= 1);
            Assert.IsTrue(result.Contracts <= 10);
            Assert.AreEqual(SizingMethod.FixedDollarRisk, result.Method);
            Assert.IsTrue(result.RiskAmount > 0);
        }

        [TestMethod]
        public void CalculateSize_InvalidStopTicks_ReturnsZeroContractsForFixedRisk()
        {
            var intent = CreateIntent(stopTicks: 0);
            var context = CreateContext();
            var config = new SizingConfig(
                method: SizingMethod.FixedDollarRisk,
                minContracts: 1,
                maxContracts: 10,
                riskPerTrade: 500,
                methodParameters: new Dictionary<string, object>());

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

            Assert.AreEqual(0, result.Contracts);
            Assert.AreEqual(0.0, result.RiskAmount);
            Assert.IsTrue(result.Calculations.ContainsKey("error"));
        }

        [TestMethod]
        public void ValidateConfig_FixedContractsWithoutContractsParam_ReturnsFalse()
        {
            var config = new SizingConfig(
                method: SizingMethod.FixedContracts,
                minContracts: 1,
                maxContracts: 10,
                riskPerTrade: 500,
                methodParameters: new Dictionary<string, object>());

            List<string> errors;
            var valid = BasicPositionSizer.ValidateConfig(config, out errors);

            Assert.IsFalse(valid);
            Assert.IsTrue(errors.Count > 0);
        }

        [TestMethod]
        public void GetMetadata_ReturnsBasicSizerName()
        {
            var metadata = _sizer.GetMetadata();

            Assert.IsNotNull(metadata);
            Assert.AreEqual("Basic Position Sizer", metadata.Name);
        }

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

        private static StrategyContext CreateContext()
        {
            return new StrategyContext(
                symbol: "ES",
                currentTime: DateTime.UtcNow,
                currentPosition: new Position("ES", 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>());
        }
    }
}
