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

namespace NT8.Adapters.Wrappers
{
    /// <summary>
    /// Base wrapper class for NT8 strategies that integrate with the SDK
    /// This is a template that would be extended in actual NT8 strategy files
    /// </summary>
    public abstract class BaseNT8StrategyWrapper
    {
        private readonly object _lock = new object();

        #region SDK Components

        protected IStrategy _sdkStrategy;
        protected IRiskManager _riskManager;
        protected IPositionSizer _positionSizer;
        protected NT8Adapter _nt8Adapter;
        protected StrategyConfig _strategyConfig;
        protected ILogger _logger;

        #endregion

        #region Properties

        /// <summary>
        /// Stop loss in ticks
        /// </summary>
        public int StopTicks { get; set; }

        /// <summary>
        /// Profit target in ticks (optional)
        /// </summary>
        public int TargetTicks { get; set; }

        /// <summary>
        /// Risk amount per trade in dollars
        /// </summary>
        public double RiskAmount { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor for BaseNT8StrategyWrapper
        /// </summary>
        public BaseNT8StrategyWrapper()
        {
            // Set default values
            StopTicks = 10;
            TargetTicks = 20;
            RiskAmount = 100.0;

            // Initialize SDK components with default implementations.
            // Derived wrappers can replace these through InitializeSdkComponents.
            _logger = new BasicLogger("BaseNT8StrategyWrapper");
            _riskManager = new BasicRiskManager(_logger);
            _positionSizer = new BasicPositionSizer(_logger);

            InitializeSdkComponents(_riskManager, _positionSizer, _logger);
        }

        #endregion

        #region Abstract Methods

        /// <summary>
        /// Create the SDK strategy implementation
        /// </summary>
        protected abstract IStrategy CreateSdkStrategy();

        #endregion

        #region Public Methods

        /// <summary>
        /// Process a bar update (would be called from NT8's OnBarUpdate)
        /// </summary>
        public void ProcessBarUpdate(BarData barData, StrategyContext context)
        {
            if (barData == null)
                throw new ArgumentNullException("barData");
            if (context == null)
                throw new ArgumentNullException("context");

            try
            {
                StrategyIntent intent;

                lock (_lock)
                {
                    if (_sdkStrategy == null)
                    {
                        throw new InvalidOperationException("SDK strategy has not been initialized.");
                    }

                    intent = _sdkStrategy.OnBar(barData, context);
                }

                if (intent != null)
                {
                    ExecuteIntent(intent, context);
                }
            }
            catch (Exception ex)
            {
                if (_logger != null)
                {
                    _logger.LogError("Failed processing bar update for {0}: {1}", context.Symbol, ex.Message);
                }

                throw;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Initialize SDK components
        /// </summary>
        protected virtual void InitializeSdkComponents(IRiskManager riskManager, IPositionSizer positionSizer, ILogger logger)
        {
            if (riskManager == null)
                throw new ArgumentNullException("riskManager");
            if (positionSizer == null)
                throw new ArgumentNullException("positionSizer");
            if (logger == null)
                throw new ArgumentNullException("logger");

            _riskManager = riskManager;
            _positionSizer = positionSizer;
            _logger = logger;

            _nt8Adapter = new NT8Adapter();
            _nt8Adapter.Initialize(_riskManager, _positionSizer);

            CreateSdkConfiguration();

            _sdkStrategy = CreateSdkStrategy();
            if (_sdkStrategy == null)
                throw new InvalidOperationException("CreateSdkStrategy returned null.");

            _sdkStrategy.Initialize(_strategyConfig, null, _logger);

            _logger.LogInformation("Base NT8 strategy wrapper initialized for symbol {0}", _strategyConfig.Symbol);
        }

        /// <summary>
        /// Create SDK configuration from parameters
        /// </summary>
        private void CreateSdkConfiguration()
        {
            // Create risk configuration
            var riskConfig = new RiskConfig(
                dailyLossLimit: 500.0,
                maxTradeRisk: RiskAmount,
                maxOpenPositions: 5,
                emergencyFlattenEnabled: true
            );

            // Create sizing configuration
            var sizingConfig = new SizingConfig(
                method: SizingMethod.FixedDollarRisk,
                minContracts: 1,
                maxContracts: 100,
                riskPerTrade: RiskAmount,
                methodParameters: new Dictionary<string, object>()
            );

            // Create strategy configuration
            _strategyConfig = new StrategyConfig(
                name: "NT8Strategy",
                symbol: "Unknown",
                parameters: new Dictionary<string, object>(),
                riskSettings: riskConfig,
                sizingSettings: sizingConfig
            );
        }

        /// <summary>
        /// Execute strategy intent through NT8
        /// </summary>
        private void ExecuteIntent(StrategyIntent intent, StrategyContext context)
        {
            if (intent == null)
                throw new ArgumentNullException("intent");
            if (context == null)
                throw new ArgumentNullException("context");

            try
            {
                SizingResult sizingResult;

                lock (_lock)
                {
                    if (_positionSizer == null)
                    {
                        throw new InvalidOperationException("Position sizer has not been initialized.");
                    }

                    sizingResult = _positionSizer.CalculateSize(intent, context, _strategyConfig.SizingSettings);
                }

                _nt8Adapter.ExecuteIntent(intent, sizingResult);
            }
            catch (Exception ex)
            {
                if (_logger != null)
                {
                    _logger.LogError("Failed executing intent for {0}: {1}", intent.Symbol, ex.Message);
                }

                throw;
            }
        }

        #endregion
    }
}
