using System;

namespace NT8.Core.Execution
{
    /// <summary>
    /// Execution metrics for a single order execution
    /// </summary>
    public class ExecutionMetrics
    {
        /// <summary>
        /// Order ID for the executed order
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Time when order intent was formed
        /// </summary>
        public DateTime IntentTime { get; set; }

        /// <summary>
        /// Time when order was submitted to market
        /// </summary>
        public DateTime SubmitTime { get; set; }

        /// <summary>
        /// Time when order was filled
        /// </summary>
        public DateTime FillTime { get; set; }

        /// <summary>
        /// Intended price when order was placed
        /// </summary>
        public decimal IntendedPrice { get; set; }

        /// <summary>
        /// Actual fill price
        /// </summary>
        public decimal FillPrice { get; set; }

        /// <summary>
        /// Price slippage (fill price - intended price)
        /// </summary>
        public decimal Slippage { get; set; }

        /// <summary>
        /// Type of slippage (positive/negative/zero)
        /// </summary>
        public SlippageType SlippageType { get; set; }

        /// <summary>
        /// Time between submit and fill
        /// </summary>
        public TimeSpan SubmitLatency { get; set; }

        /// <summary>
        /// Time between fill and intent
        /// </summary>
        public TimeSpan FillLatency { get; set; }

        /// <summary>
        /// Overall execution quality rating
        /// </summary>
        public ExecutionQuality Quality { get; set; }

        /// <summary>
        /// Constructor for ExecutionMetrics
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="intentTime">Intent formation time</param>
        /// <param name="submitTime">Submission time</param>
        /// <param name="fillTime">Fill time</param>
        /// <param name="intendedPrice">Intended price</param>
        /// <param name="fillPrice">Actual fill price</param>
        /// <param name="slippage">Price slippage</param>
        /// <param name="slippageType">Type of slippage</param>
        /// <param name="submitLatency">Submission latency</param>
        /// <param name="fillLatency">Fill latency</param>
        /// <param name="quality">Execution quality</param>
        public ExecutionMetrics(
            string orderId,
            DateTime intentTime,
            DateTime submitTime,
            DateTime fillTime,
            decimal intendedPrice,
            decimal fillPrice,
            decimal slippage,
            SlippageType slippageType,
            TimeSpan submitLatency,
            TimeSpan fillLatency,
            ExecutionQuality quality)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            OrderId = orderId;
            IntentTime = intentTime;
            SubmitTime = submitTime;
            FillTime = fillTime;
            IntendedPrice = intendedPrice;
            FillPrice = fillPrice;
            Slippage = slippage;
            SlippageType = slippageType;
            SubmitLatency = submitLatency;
            FillLatency = fillLatency;
            Quality = quality;
        }
    }

    /// <summary>
    /// Information about price slippage
    /// </summary>
    public class SlippageInfo
    {
        /// <summary>
        /// Order ID associated with the slippage
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Intended price
        /// </summary>
        public decimal IntendedPrice { get; set; }

        /// <summary>
        /// Actual fill price
        /// </summary>
        public decimal ActualPrice { get; set; }

        /// <summary>
        /// Calculated slippage (actual - intended)
        /// </summary>
        public decimal Slippage { get; set; }

        /// <summary>
        /// Slippage expressed in ticks
        /// </summary>
        public int SlippageInTicks { get; set; }

        /// <summary>
        /// Percentage slippage relative to intended price
        /// </summary>
        public decimal SlippagePercentage { get; set; }

        /// <summary>
        /// Type of slippage (positive/negative/zero)
        /// </summary>
        public SlippageType Type { get; set; }

        /// <summary>
        /// Constructor for SlippageInfo
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="intendedPrice">Intended price</param>
        /// <param name="actualPrice">Actual fill price</param>
        /// <param name="slippageInTicks">Slippage in ticks</param>
        /// <param name="tickSize">Size of one tick</param>
        public SlippageInfo(
            string orderId,
            decimal intendedPrice,
            decimal actualPrice,
            int slippageInTicks,
            decimal tickSize)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");
            if (tickSize <= 0)
                throw new ArgumentException("Tick size must be positive", "tickSize");

            OrderId = orderId;
            IntendedPrice = intendedPrice;
            ActualPrice = actualPrice;
            Slippage = actualPrice - intendedPrice;
            SlippageInTicks = slippageInTicks;
            SlippagePercentage = tickSize > 0 ? (Slippage / IntendedPrice) * 100 : 0;
            Type = Slippage > 0 ? SlippageType.Positive :
                   Slippage < 0 ? SlippageType.Negative : SlippageType.Zero;
        }
    }

    /// <summary>
    /// Timing information for execution
    /// </summary>
    public class ExecutionTiming
    {
        /// <summary>
        /// Time when order was created internally
        /// </summary>
        public DateTime CreateTime { get; set; }

        /// <summary>
        /// Time when order was submitted to market
        /// </summary>
        public DateTime SubmitTime { get; set; }

        /// <summary>
        /// Time when order was acknowledged by market
        /// </summary>
        public DateTime AckTime { get; set; }

        /// <summary>
        /// Time when order was filled
        /// </summary>
        public DateTime FillTime { get; set; }

        /// <summary>
        /// Latency from create to submit
        /// </summary>
        public TimeSpan CreateToSubmitLatency { get; set; }

        /// <summary>
        /// Latency from submit to acknowledge
        /// </summary>
        public TimeSpan SubmitToAckLatency { get; set; }

        /// <summary>
        /// Latency from acknowledge to fill
        /// </summary>
        public TimeSpan AckToFillLatency { get; set; }

        /// <summary>
        /// Total execution latency
        /// </summary>
        public TimeSpan TotalLatency { get; set; }

        /// <summary>
        /// Constructor for ExecutionTiming
        /// </summary>
        /// <param name="createTime">Creation time</param>
        /// <param name="submitTime">Submission time</param>
        /// <param name="ackTime">Acknowledgment time</param>
        /// <param name="fillTime">Fill time</param>
        public ExecutionTiming(
            DateTime createTime,
            DateTime submitTime,
            DateTime ackTime,
            DateTime fillTime)
        {
            CreateTime = createTime;
            SubmitTime = submitTime;
            AckTime = ackTime;
            FillTime = fillTime;

            CreateToSubmitLatency = SubmitTime - CreateTime;
            SubmitToAckLatency = AckTime - SubmitTime;
            AckToFillLatency = FillTime - AckTime;
            TotalLatency = FillTime - CreateTime;
        }
    }

    /// <summary>
    /// Enum representing execution quality levels
    /// </summary>
    public enum ExecutionQuality
    {
        /// <summary>
        /// Excellent execution with minimal slippage
        /// </summary>
        Excellent = 0,

        /// <summary>
        /// Good execution with acceptable slippage
        /// </summary>
        Good = 1,

        /// <summary>
        /// Fair execution with moderate slippage
        /// </summary>
        Fair = 2,

        /// <summary>
        /// Poor execution with significant slippage
        /// </summary>
        Poor = 3
    }

    /// <summary>
    /// Enum representing type of slippage
    /// </summary>
    public enum SlippageType
    {
        /// <summary>
        /// Positive slippage (better than expected)
        /// </summary>
        Positive = 0,

        /// <summary>
        /// Negative slippage (worse than expected)
        /// </summary>
        Negative = 1,

        /// <summary>
        /// No slippage (as expected)
        /// </summary>
        Zero = 2
    }
}
