using System;
using System.Collections.Generic;

namespace NT8.Core.Risk
{
    /// <summary>
    /// Represents different risk modes that can be applied to strategies.
    /// </summary>
    public enum RiskMode
    {
        /// <summary>
        /// Standard, normal risk settings.
        /// </summary>
        Standard,
        /// <summary>
        /// Conservative risk settings, lower exposure.
        /// </summary>
        Conservative,
        /// <summary>
        /// Aggressive risk settings, higher exposure.
        /// </summary>
        Aggressive,
        /// <summary>
        /// Emergency flatten mode, no new trades, close existing.
        /// </summary>
        EmergencyFlatten
    }

    /// <summary>
    /// Represents a time window for trading restrictions.
    /// </summary>
    public class TradingTimeWindow
    {
        /// <summary>
        /// Gets the start time of the window.
        /// </summary>
        public TimeSpan StartTime { get; private set; }

        /// <summary>
        /// Gets the end time of the window.
        /// </summary>
        public TimeSpan EndTime { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="TradingTimeWindow"/> class.
        /// </summary>
        /// <param name="startTime">The start time of the window.</param>
        /// <param name="endTime">The end time of the window.</param>
        public TradingTimeWindow(TimeSpan startTime, TimeSpan endTime)
        {
            StartTime = startTime;
            EndTime = endTime;
        }
    }

    /// <summary>
    /// Represents the configuration for advanced risk management.
    /// </summary>
    public class AdvancedRiskConfig
    {
        /// <summary>
        /// Gets the maximum weekly loss limit.
        /// </summary>
        public double WeeklyLossLimit { get; private set; }

        /// <summary>
        /// Gets the trailing drawdown limit.
        /// </summary>
        public double TrailingDrawdownLimit { get; private set; }

        /// <summary>
        /// Gets the maximum exposure allowed across all strategies.
        /// </summary>
        public double? MaxCrossStrategyExposure { get; private set; }

        /// <summary>
        /// Gets the duration of the cooldown period after a risk breach.
        /// </summary>
        public TimeSpan CooldownDuration { get; private set; }

        /// <summary>
        /// Gets the maximum correlated exposure across instruments.
        /// </summary>
        public double? MaxCorrelatedExposure { get; private set; }

        /// <summary>
        /// Gets the list of allowed trading time windows.
        /// </summary>
        public List<TradingTimeWindow> TradingTimeWindows { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AdvancedRiskConfig"/> class.
        /// </summary>
        /// <param name="weeklyLossLimit">The maximum weekly loss limit.</param>
        /// <param name="trailingDrawdownLimit">The trailing drawdown limit.</param>
        /// <param name="maxCrossStrategyExposure">The maximum exposure allowed across all strategies.</param>
        /// <param name="cooldownDuration">The duration of the cooldown period after a risk breach.</param>
        /// <param name="maxCorrelatedExposure">The maximum correlated exposure across instruments.</param>
        /// <param name="tradingTimeWindows">The list of allowed trading time windows.</param>
        public AdvancedRiskConfig(
            double weeklyLossLimit,
            double trailingDrawdownLimit,
            double? maxCrossStrategyExposure,
            TimeSpan cooldownDuration,
            double? maxCorrelatedExposure,
            List<TradingTimeWindow> tradingTimeWindows)
        {
            WeeklyLossLimit = weeklyLossLimit;
            TrailingDrawdownLimit = trailingDrawdownLimit;
            MaxCrossStrategyExposure = maxCrossStrategyExposure;
            CooldownDuration = cooldownDuration;
            MaxCorrelatedExposure = maxCorrelatedExposure;
            TradingTimeWindows = tradingTimeWindows ?? new List<TradingTimeWindow>();
        }
    }

    /// <summary>
    /// Represents the current state of advanced risk management.
    /// </summary>
    public class AdvancedRiskState
    {
        /// <summary>
        /// Gets the current weekly PnL.
        /// </summary>
        public double WeeklyPnL { get; private set; }

        /// <summary>
        /// Gets the date of the start of the current weekly tracking period.
        /// </summary>
        public DateTime WeekStartDate { get; private set; }

        /// <summary>
        /// Gets the current trailing drawdown.
        /// </summary>
        public double TrailingDrawdown { get; private set; }

        /// <summary>
        /// Gets the highest point reached in equity or PnL.
        /// </summary>
        public double PeakEquity { get; private set; }

        /// <summary>
        /// Gets the list of active strategies.
        /// </summary>
        public List<string> ActiveStrategies { get; private set; }

        /// <summary>
        /// Gets the exposure by symbol.
        /// </summary>
        public Dictionary<string, double> ExposureBySymbol { get; private set; }

        /// <summary>
        /// Gets the correlated exposure.
        /// </summary>
        public double CorrelatedExposure { get; private set; }

        /// <summary>
        /// Gets the last time the state was updated.
        /// </summary>
        public DateTime LastStateUpdate { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AdvancedRiskState"/> class.
        /// </summary>
        /// <param name="weeklyPnL">The current weekly PnL.</param>
        /// <param name="weekStartDate">The date of the start of the current weekly tracking period.</param>
        /// <param name="trailingDrawdown">The current trailing drawdown.</param>
        /// <param name="peakEquity">The highest point reached in equity or PnL.</param>
        /// <param name="activeStrategies">The list of active strategies.</param>
        /// <param name="exposureBySymbol">The exposure by symbol.</param>
        /// <param name="correlatedExposure">The correlated exposure.</param>
        /// <param name="lastStateUpdate">The last time the state was updated.</param>
        public AdvancedRiskState(
            double weeklyPnL,
            DateTime weekStartDate,
            double trailingDrawdown,
            double peakEquity,
            List<string> activeStrategies,
            Dictionary<string, double> exposureBySymbol,
            double correlatedExposure,
            DateTime lastStateUpdate)
        {
            WeeklyPnL = weeklyPnL;
            WeekStartDate = weekStartDate;
            TrailingDrawdown = trailingDrawdown;
            PeakEquity = peakEquity;
            ActiveStrategies = activeStrategies ?? new List<string>();
            ExposureBySymbol = exposureBySymbol ?? new Dictionary<string, double>();
            CorrelatedExposure = correlatedExposure;
            LastStateUpdate = lastStateUpdate;
        }
    }

    /// <summary>
    /// Represents the exposure of a single strategy.
    /// </summary>
    public class StrategyExposure
    {
        private readonly object _lock = new object();

        /// <summary>
        /// Gets the unique identifier for the strategy.
        /// </summary>
        public string StrategyId { get; private set; }

        /// <summary>
        /// Gets the current net exposure (longs - shorts) for the strategy.
        /// </summary>
        public double NetExposure { get; private set; }

        /// <summary>
        /// Gets the gross exposure (absolute sum of longs and shorts) for the strategy.
        /// </summary>
        public double GrossExposure { get; private set; }

        /// <summary>
        /// Gets the number of open positions for the strategy.
        /// </summary>
        public int OpenPositions { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="StrategyExposure"/> class.
        /// </summary>
        /// <param name="strategyId">The unique identifier for the strategy.</param>
        public StrategyExposure(string strategyId)
        {
            if (strategyId == null) throw new ArgumentNullException("strategyId");
            StrategyId = strategyId;
            NetExposure = 0;
            GrossExposure = 0;
            OpenPositions = 0;
        }

        /// <summary>
        /// Updates the strategy's exposure.
        /// </summary>
        /// <param name="netChange">The change in net exposure.</param>
        /// <param name="grossChange">The change in gross exposure.</param>
        /// <param name="positionsChange">The change in open positions.</param>
        public void Update(double netChange, double grossChange, int positionsChange)
        {
            lock (_lock)
            {
                NetExposure = NetExposure + netChange;
                GrossExposure = GrossExposure + grossChange;
                OpenPositions = OpenPositions + positionsChange;
            }
        }

        /// <summary>
        /// Resets the strategy exposure.
        /// </summary>
        public void Reset()
        {
            lock (_lock)
            {
                NetExposure = 0;
                GrossExposure = 0;
                OpenPositions = 0;
            }
        }
    }
}
