using System;
using System.Collections.Generic;
using NT8.Core.Common.Interfaces;
using NT8.Core.Common.Models;
using NT8.Core.Logging;
using NT8.Adapters.NinjaTrader;

namespace NT8.Adapters.Wrappers
{
    /// <summary>
    /// Simple ORB (Opening Range Breakout) strategy wrapper for NT8
    /// This demonstrates how to implement a strategy that works with the SDK
    /// </summary>
    public class SimpleORBNT8Wrapper : BaseNT8StrategyWrapper
    {
        #region Strategy Parameters

        /// <summary>
        /// Opening range period in minutes
        /// </summary>
        public int OpeningRangeMinutes { get; set; }

        /// <summary>
        /// Number of standard deviations for breakout threshold
        /// </summary>
        public double StdDevMultiplier { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor for SimpleORBNT8Wrapper
        /// </summary>
        public SimpleORBNT8Wrapper()
        {
            OpeningRangeMinutes = 30;
            StdDevMultiplier = 1.0;
        }

        #endregion

        #region Base Class Implementation

        /// <summary>
        /// Exposes adapter reference for integration test assertions.
        /// </summary>
        public NT8Adapter GetAdapterForTesting()
        {
            return _nt8Adapter;
        }

        /// <summary>
        /// Create the SDK strategy implementation
        /// </summary>
        protected override IStrategy CreateSdkStrategy()
        {
            var openingRangeMinutes = OpeningRangeMinutes > 0 ? OpeningRangeMinutes : 30;
            var stdDevMultiplier = StdDevMultiplier > 0.0 ? StdDevMultiplier : 1.0;
            return new SimpleORBStrategy(openingRangeMinutes, stdDevMultiplier);
        }

        #endregion

        #region Strategy Logic

        /// <summary>
        /// Simple ORB strategy implementation
        /// </summary>
        private class SimpleORBStrategy : IStrategy
        {
            private readonly int _openingRangeMinutes;
            private readonly double _stdDevMultiplier;

            private ILogger _logger;
            private DateTime _currentSessionDate;
            private DateTime _openingRangeStart;
            private DateTime _openingRangeEnd;
            private double _openingRangeHigh;
            private double _openingRangeLow;
            private bool _openingRangeReady;
            private bool _tradeTaken;

            public StrategyMetadata Metadata { get; private set; }

            public SimpleORBStrategy(int openingRangeMinutes, double stdDevMultiplier)
            {
                if (openingRangeMinutes <= 0)
                {
                    throw new ArgumentException("openingRangeMinutes");
                }

                if (stdDevMultiplier <= 0.0)
                {
                    throw new ArgumentException("stdDevMultiplier");
                }

                _openingRangeMinutes = openingRangeMinutes;
                _stdDevMultiplier = stdDevMultiplier;

                _currentSessionDate = DateTime.MinValue;
                _openingRangeStart = DateTime.MinValue;
                _openingRangeEnd = DateTime.MinValue;
                _openingRangeHigh = Double.MinValue;
                _openingRangeLow = Double.MaxValue;
                _openingRangeReady = false;
                _tradeTaken = false;

                Metadata = new StrategyMetadata(
                    name: "Simple ORB",
                    description: "Opening Range Breakout strategy",
                    version: "1.0",
                    author: "NT8 SDK Team",
                    symbols: new string[] { "ES", "NQ", "YM" },
                    requiredBars: 20
                );
            }

            public void Initialize(StrategyConfig config, IMarketDataProvider dataProvider, ILogger logger)
            {
                if (logger == null)
                {
                    throw new ArgumentNullException("logger");
                }

                _logger = logger;
                _logger.LogInformation("SimpleORBStrategy initialized with OR period {0} minutes and multiplier {1:F2}", _openingRangeMinutes, _stdDevMultiplier);
            }

            public StrategyIntent OnBar(BarData bar, StrategyContext context)
            {
                if (bar == null)
                {
                    throw new ArgumentNullException("bar");
                }

                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                try
                {
                    if (_currentSessionDate != context.CurrentTime.Date)
                    {
                        ResetSession(context.Session.SessionStart);
                    }

                    if (bar.Time <= _openingRangeEnd)
                    {
                        UpdateOpeningRange(bar);
                        return null;
                    }

                    if (!_openingRangeReady)
                    {
                        if (_openingRangeHigh > _openingRangeLow)
                        {
                            _openingRangeReady = true;
                        }
                        else
                        {
                            return null;
                        }
                    }

                    if (_tradeTaken)
                    {
                        return null;
                    }

                    var openingRange = _openingRangeHigh - _openingRangeLow;
                    var volatilityBuffer = openingRange * (_stdDevMultiplier - 1.0);
                    if (volatilityBuffer < 0)
                    {
                        volatilityBuffer = 0;
                    }

                    var longTrigger = _openingRangeHigh + volatilityBuffer;
                    var shortTrigger = _openingRangeLow - volatilityBuffer;

                    if (bar.Close > longTrigger)
                    {
                        _tradeTaken = true;
                        return CreateIntent(context.Symbol, OrderSide.Buy, openingRange, bar.Close);
                    }

                    if (bar.Close < shortTrigger)
                    {
                        _tradeTaken = true;
                        return CreateIntent(context.Symbol, OrderSide.Sell, openingRange, bar.Close);
                    }

                    return null;
                }
                catch (Exception ex)
                {
                    if (_logger != null)
                    {
                        _logger.LogError("SimpleORBStrategy OnBar failed: {0}", ex.Message);
                    }

                    throw;
                }
            }

            public StrategyIntent OnTick(TickData tick, StrategyContext context)
            {
                // Most strategies don't need tick-level logic
                return null;
            }

            public Dictionary<string, object> GetParameters()
            {
                var parameters = new Dictionary<string, object>();
                parameters.Add("opening_range_minutes", _openingRangeMinutes);
                parameters.Add("std_dev_multiplier", _stdDevMultiplier);
                return parameters;
            }

            public void SetParameters(Dictionary<string, object> parameters)
            {
                // Parameters are constructor-bound for deterministic behavior in this wrapper.
                // Method retained for interface compatibility.
            }

            private void ResetSession(DateTime sessionStart)
            {
                _currentSessionDate = sessionStart.Date;
                _openingRangeStart = sessionStart;
                _openingRangeEnd = sessionStart.AddMinutes(_openingRangeMinutes);
                _openingRangeHigh = Double.MinValue;
                _openingRangeLow = Double.MaxValue;
                _openingRangeReady = false;
                _tradeTaken = false;
            }

            private void UpdateOpeningRange(BarData bar)
            {
                if (bar.High > _openingRangeHigh)
                {
                    _openingRangeHigh = bar.High;
                }

                if (bar.Low < _openingRangeLow)
                {
                    _openingRangeLow = bar.Low;
                }
            }

            private StrategyIntent CreateIntent(string symbol, OrderSide side, double openingRange, double lastPrice)
            {
                var metadata = new Dictionary<string, object>();
                metadata.Add("orb_high", _openingRangeHigh);
                metadata.Add("orb_low", _openingRangeLow);
                metadata.Add("orb_range", openingRange);
                metadata.Add("trigger_price", lastPrice);
                metadata.Add("multiplier", _stdDevMultiplier);

                if (_logger != null)
                {
                    _logger.LogInformation("SimpleORBStrategy generated {0} intent for {1}. OR High={2:F2}, OR Low={3:F2}, Last={4:F2}", side, symbol, _openingRangeHigh, _openingRangeLow, lastPrice);
                }

                return new StrategyIntent(
                    symbol,
                    side,
                    OrderType.Market,
                    null,
                    8,
                    16,
                    0.75,
                    "ORB breakout signal",
                    metadata);
            }
        }

        #endregion
    }
}
