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

namespace NT8.Core.Tests.Analytics
{
    [TestClass]
    public class PnLAttributorTests
    {
        private PnLAttributor _target;

        [TestInitialize]
        public void TestInitialize()
        {
            _target = new PnLAttributor(new BasicLogger("PnLAttributorTests"));
        }

        [TestMethod] public void AttributeByGrade_ReturnsSlices() { var r = _target.AttributeByGrade(Sample()); Assert.IsTrue(r.Slices.Count > 0); }
        [TestMethod] public void AttributeByRegime_ReturnsSlices() { var r = _target.AttributeByRegime(Sample()); Assert.IsTrue(r.Slices.Count > 0); }
        [TestMethod] public void AttributeByStrategy_ReturnsSlices() { var r = _target.AttributeByStrategy(Sample()); Assert.IsTrue(r.Slices.Count > 0); }
        [TestMethod] public void AttributeByTimeOfDay_ReturnsSlices() { var r = _target.AttributeByTimeOfDay(Sample()); Assert.IsTrue(r.Slices.Count > 0); }
        [TestMethod] public void MultiDimensional_ReturnsSlices() { var r = _target.AttributeMultiDimensional(Sample(), new List<AttributionDimension> { AttributionDimension.Grade, AttributionDimension.Strategy }); Assert.IsTrue(r.Slices.Count > 0); }
        [TestMethod] public void MultiDimensional_EmptyDims_Throws() { Assert.ThrowsException<ArgumentException>(() => _target.AttributeMultiDimensional(Sample(), new List<AttributionDimension>())); }
        [TestMethod] public void Grade_Null_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeByGrade(null)); }
        [TestMethod] public void Regime_Null_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeByRegime(null)); }
        [TestMethod] public void Strategy_Null_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeByStrategy(null)); }
        [TestMethod] public void Time_Null_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeByTimeOfDay(null)); }
        [TestMethod] public void Multi_NullTrades_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeMultiDimensional(null, new List<AttributionDimension> { AttributionDimension.Strategy })); }
        [TestMethod] public void Multi_NullDims_Throws() { Assert.ThrowsException<ArgumentNullException>(() => _target.AttributeMultiDimensional(Sample(), null)); }
        [TestMethod] public void Contribution_SumsCloseToOneWhenTotalNonZero() { var r = _target.AttributeByStrategy(Sample()); var sum = 0.0; foreach (var s in r.Slices) sum += s.Contribution; Assert.IsTrue(sum > 0.5 && sum < 1.5); }
        [TestMethod] public void Slice_HasDimensionName() { var r = _target.AttributeByGrade(Sample()); Assert.IsFalse(string.IsNullOrEmpty(r.Slices[0].DimensionName)); }
        [TestMethod] public void Slice_WinRateInRange() { var r = _target.AttributeByGrade(Sample()); Assert.IsTrue(r.Slices[0].WinRate >= 0 && r.Slices[0].WinRate <= 1); }
        [TestMethod] public void Report_TotalTradesMatches() { var s = Sample(); var r = _target.AttributeByGrade(s); Assert.AreEqual(s.Count, r.TotalTrades); }
        [TestMethod] public void Report_TotalPnLMatches() { var s = Sample(); var r = _target.AttributeByGrade(s); double p = 0; foreach (var t in s) p += t.RealizedPnL; Assert.AreEqual(p, r.TotalPnL, 0.0001); }
        [TestMethod] public void TimeBuckets_Assigned() { var r = _target.AttributeByTimeOfDay(Sample()); Assert.IsTrue(r.Slices.Count > 0); }

        private static List<TradeRecord> Sample()
        {
            return new List<TradeRecord>
            {
                Trade("S1", TradeGrade.A, 50, VolatilityRegime.Normal, TrendRegime.StrongUp, DateTime.UtcNow.Date.AddHours(9.5)),
                Trade("S1", TradeGrade.B, -20, VolatilityRegime.Elevated, TrendRegime.Range, DateTime.UtcNow.Date.AddHours(11)),
                Trade("S2", TradeGrade.C, 30, VolatilityRegime.Low, TrendRegime.WeakUp, DateTime.UtcNow.Date.AddHours(15.5)),
                Trade("S2", TradeGrade.A, -10, VolatilityRegime.Normal, TrendRegime.WeakDown, DateTime.UtcNow.Date.AddHours(10))
            };
        }

        private static TradeRecord Trade(string strategy, TradeGrade grade, double pnl, VolatilityRegime vol, TrendRegime trend, DateTime time)
        {
            var t = new TradeRecord();
            t.TradeId = Guid.NewGuid().ToString();
            t.Symbol = "ES";
            t.StrategyName = strategy;
            t.EntryTime = time;
            t.ExitTime = time.AddMinutes(5);
            t.Side = OrderSide.Buy;
            t.Quantity = 1;
            t.EntryPrice = 100;
            t.ExitPrice = 101;
            t.RealizedPnL = pnl;
            t.Grade = grade;
            t.RiskMode = RiskMode.PCP;
            t.VolatilityRegime = vol;
            t.TrendRegime = trend;
            t.StopTicks = 8;
            t.TargetTicks = 16;
            t.Duration = TimeSpan.FromMinutes(5);
            return t;
        }
    }
}

