using System;
using System.Collections.Generic;
using NT8.Core.Common.Models;

namespace NT8.Adapters.NinjaTrader
{
    /// <summary>
    /// Converts NinjaTrader adapter inputs to SDK model instances.
    /// </summary>
    public static class NT8DataConverter
    {
        /// <summary>
        /// Converts primitive bar inputs into SDK bar data.
        /// </summary>
        /// <param name="symbol">Instrument symbol.</param>
        /// <param name="time">Bar timestamp.</param>
        /// <param name="open">Open price.</param>
        /// <param name="high">High price.</param>
        /// <param name="low">Low price.</param>
        /// <param name="close">Close price.</param>
        /// <param name="volume">Bar volume.</param>
        /// <param name="barSizeMinutes">Bar timeframe in minutes.</param>
        /// <returns>Converted <see cref="BarData"/> instance.</returns>
        /// <exception cref="ArgumentException">Thrown when symbol is missing or bar size is invalid.</exception>
        public static BarData ConvertBar(string symbol, DateTime time, double open, double high, double low, double close, long volume, int barSizeMinutes)
        {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                throw new ArgumentException("symbol");
            }

            if (barSizeMinutes <= 0)
            {
                throw new ArgumentException("barSizeMinutes");
            }

            try
            {
                return new BarData(symbol, time, open, high, low, close, volume, TimeSpan.FromMinutes(barSizeMinutes));
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Converts account values into SDK account info.
        /// </summary>
        /// <param name="equity">Current account equity.</param>
        /// <param name="buyingPower">Available buying power.</param>
        /// <param name="dailyPnL">Current day profit and loss.</param>
        /// <param name="maxDrawdown">Maximum drawdown value.</param>
        /// <param name="lastUpdate">Last account update timestamp.</param>
        /// <returns>Converted <see cref="AccountInfo"/> instance.</returns>
        public static AccountInfo ConvertAccount(double equity, double buyingPower, double dailyPnL, double maxDrawdown, DateTime lastUpdate)
        {
            try
            {
                return new AccountInfo(equity, buyingPower, dailyPnL, maxDrawdown, lastUpdate);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Converts position values into SDK position info.
        /// </summary>
        /// <param name="symbol">Instrument symbol.</param>
        /// <param name="quantity">Position quantity.</param>
        /// <param name="averagePrice">Average entry price.</param>
        /// <param name="unrealizedPnL">Unrealized PnL value.</param>
        /// <param name="realizedPnL">Realized PnL value.</param>
        /// <param name="lastUpdate">Last position update timestamp.</param>
        /// <returns>Converted <see cref="Position"/> instance.</returns>
        /// <exception cref="ArgumentException">Thrown when symbol is missing.</exception>
        public static Position ConvertPosition(string symbol, int quantity, double averagePrice, double unrealizedPnL, double realizedPnL, DateTime lastUpdate)
        {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                throw new ArgumentException("symbol");
            }

            try
            {
                return new Position(symbol, quantity, averagePrice, unrealizedPnL, realizedPnL, lastUpdate);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Converts market session values into SDK market session.
        /// </summary>
        /// <param name="sessionStart">Session start timestamp.</param>
        /// <param name="sessionEnd">Session end timestamp.</param>
        /// <param name="isRth">True for regular trading hours session.</param>
        /// <param name="sessionName">Session display name.</param>
        /// <returns>Converted <see cref="MarketSession"/> instance.</returns>
        /// <exception cref="ArgumentException">Thrown when session name is missing or session range is invalid.</exception>
        public static MarketSession ConvertSession(DateTime sessionStart, DateTime sessionEnd, bool isRth, string sessionName)
        {
            if (string.IsNullOrWhiteSpace(sessionName))
            {
                throw new ArgumentException("sessionName");
            }

            if (sessionEnd < sessionStart)
            {
                throw new ArgumentException("sessionEnd");
            }

            try
            {
                return new MarketSession(sessionStart, sessionEnd, isRth, sessionName);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Converts values into SDK strategy context.
        /// </summary>
        /// <param name="symbol">Instrument symbol.</param>
        /// <param name="currentTime">Current timestamp.</param>
        /// <param name="currentPosition">Current position info.</param>
        /// <param name="account">Current account info.</param>
        /// <param name="session">Current market session.</param>
        /// <param name="customData">Custom data dictionary.</param>
        /// <returns>Converted <see cref="StrategyContext"/> instance.</returns>
        /// <exception cref="ArgumentException">Thrown when symbol is missing.</exception>
        /// <exception cref="ArgumentNullException">Thrown when required objects are null.</exception>
        public static StrategyContext ConvertContext(
            string symbol,
            DateTime currentTime,
            Position currentPosition,
            AccountInfo account,
            MarketSession session,
            Dictionary<string, object> customData)
        {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                throw new ArgumentException("symbol");
            }

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

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

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

            Dictionary<string, object> convertedCustomData;
            if (customData == null)
            {
                convertedCustomData = new Dictionary<string, object>();
            }
            else
            {
                convertedCustomData = new Dictionary<string, object>();
                foreach (var pair in customData)
                {
                    convertedCustomData.Add(pair.Key, pair.Value);
                }
            }

            try
            {
                return new StrategyContext(symbol, currentTime, currentPosition, account, session, convertedCustomData);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
