using System;
using System.Collections.Generic;

namespace NT8.Core.OMS
{
    #region Enumerations

    /// <summary>
    /// Order side enumeration
    /// </summary>
    public enum OrderSide
    {
        Buy = 1,
        Sell = -1
    }

    /// <summary>
    /// Order type enumeration
    /// </summary>
    public enum OrderType
    {
        Market,
        Limit,
        StopMarket,
        StopLimit
    }

    /// <summary>
    /// Order state enumeration for the OMS state machine
    /// </summary>
    public enum OrderState
    {
        Pending,           // Order request created, waiting for risk approval
        Submitted,         // Sent to broker, waiting for acceptance
        Accepted,          // Broker accepted the order
        Working,           // Order is live in the market
        PartiallyFilled,   // Order partially filled
        Filled,            // Order completely filled
        Cancelled,         // Order cancelled by user or system
        Rejected,          // Order rejected by broker or system
        Expired            // Order expired
    }

    /// <summary>
    /// Time in force enumeration
    /// </summary>
    public enum TimeInForce
    {
        Day,
        Gtc, // Good Till Cancelled
        Ioc, // Immediate Or Cancel
        Fok  // Fill Or Kill
    }

    #endregion

    #region Core Order Models

    /// <summary>
    /// Order request parameters
    /// </summary>
    public class OrderRequest
    {
        /// <summary>
        /// Trading symbol
        /// </summary>
        public string Symbol { get; set; }

        /// <summary>
        /// Order side
        /// </summary>
        public OrderSide Side { get; set; }

        /// <summary>
        /// Order type
        /// </summary>
        public OrderType Type { get; set; }

        /// <summary>
        /// Order quantity
        /// </summary>
        public int Quantity { get; set; }

        /// <summary>
        /// Limit price (if applicable)
        /// </summary>
        public decimal? LimitPrice { get; set; }

        /// <summary>
        /// Stop price (if applicable)
        /// </summary>
        public decimal? StopPrice { get; set; }

        /// <summary>
        /// Time in force
        /// </summary>
        public TimeInForce TimeInForce { get; set; }

        /// <summary>
        /// Unique identifier for this order request
        /// </summary>
        public string ClientOrderId { get; set; }

        /// <summary>
        /// Timestamp when order was created
        /// </summary>
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// Constructor for OrderRequest
        /// </summary>
        public OrderRequest()
        {
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Order submission result
    /// </summary>
    public class OrderResult
    {
        /// <summary>
        /// Whether the order submission was successful
        /// </summary>
        public bool Success { get; set; }

        /// <summary>
        /// Order ID if successful
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Message describing the result
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// Original order request
        /// </summary>
        public OrderRequest Request { get; set; }

        /// <summary>
        /// Constructor for OrderResult
        /// </summary>
        public OrderResult(bool success, string orderId, string message, OrderRequest request)
        {
            Success = success;
            OrderId = orderId;
            Message = message;
            Request = request;
        }
    }

    /// <summary>
    /// Current order status with full state information
    /// </summary>
    public class OrderStatus
    {
        /// <summary>
        /// Internal order ID assigned by the OMS
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Client-provided order ID
        /// </summary>
        public string ClientOrderId { get; set; }

        /// <summary>
        /// Trading symbol
        /// </summary>
        public string Symbol { get; set; }

        /// <summary>
        /// Order side
        /// </summary>
        public OrderSide Side { get; set; }

        /// <summary>
        /// Order type
        /// </summary>
        public OrderType Type { get; set; }

        /// <summary>
        /// Original order quantity
        /// </summary>
        public int Quantity { get; set; }

        /// <summary>
        /// Filled quantity
        /// </summary>
        public int FilledQuantity { get; set; }

        /// <summary>
        /// Remaining quantity
        /// </summary>
        public int RemainingQuantity { get { return Quantity - FilledQuantity; } }

        /// <summary>
        /// Limit price (if applicable)
        /// </summary>
        public decimal? LimitPrice { get; set; }

        /// <summary>
        /// Stop price (if applicable)
        /// </summary>
        public decimal? StopPrice { get; set; }

        /// <summary>
        /// Current order state
        /// </summary>
        public OrderState State { get; set; }

        /// <summary>
        /// Order creation time
        /// </summary>
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// Order fill time (if filled)
        /// </summary>
        public DateTime? FilledTime { get; set; }

        /// <summary>
        /// Order fills
        /// </summary>
        public List<OrderFill> Fills { get; set; }

        /// <summary>
        /// Average fill price
        /// </summary>
        public decimal AverageFillPrice { get; set; }

        /// <summary>
        /// Total value of filled shares
        /// </summary>
        public decimal FillValue { get; set; }

        /// <summary>
        /// Constructor for OrderStatus
        /// </summary>
        public OrderStatus()
        {
            Fills = new List<OrderFill>();
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Represents a single fill event for an order
    /// </summary>
    public class OrderFill
    {
        /// <summary>
        /// Fill ID from the broker
        /// </summary>
        public string FillId { get; set; }

        /// <summary>
        /// Order ID this fill belongs to
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Quantity filled in this transaction
        /// </summary>
        public int FillQuantity { get; set; }

        /// <summary>
        /// Price at which the fill occurred
        /// </summary>
        public decimal FillPrice { get; set; }

        /// <summary>
        /// Timestamp of the fill
        /// </summary>
        public DateTime FillTime { get; set; }

        /// <summary>
        /// Commission paid for this fill
        /// </summary>
        public decimal Commission { get; set; }

        /// <summary>
        /// Constructor for OrderFill
        /// </summary>
        public OrderFill()
        {
            FillTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Order modification parameters
    /// </summary>
    public class OrderModification
    {
        /// <summary>
        /// Order ID to modify
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// New quantity (if changing)
        /// </summary>
        public int? NewQuantity { get; set; }

        /// <summary>
        /// New limit price (if changing)
        /// </summary>
        public decimal? NewLimitPrice { get; set; }

        /// <summary>
        /// New stop price (if changing)
        /// </summary>
        public decimal? NewStopPrice { get; set; }

        /// <summary>
        /// New time in force (if changing)
        /// </summary>
        public TimeInForce? NewTimeInForce { get; set; }

        /// <summary>
        /// Constructor for OrderModification
        /// </summary>
        public OrderModification(string orderId)
        {
            OrderId = orderId;
        }
    }

    /// <summary>
    /// Order cancellation request
    /// </summary>
    public class OrderCancellation
    {
        /// <summary>
        /// Order ID to cancel
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Reason for cancellation
        /// </summary>
        public string Reason { get; set; }

        /// <summary>
        /// Constructor for OrderCancellation
        /// </summary>
        public OrderCancellation(string orderId, string reason)
        {
            OrderId = orderId;
            Reason = reason;
        }
    }

    #endregion

    #region Phase 2 - Partial Fill Models

    /// <summary>
    /// Detailed information about a partial fill event
    /// </summary>
    public class PartialFillInfo
    {
        /// <summary>
        /// Order ID this partial fill belongs to
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Quantity filled in this event
        /// </summary>
        public int FilledQuantity { get; set; }

        /// <summary>
        /// Remaining quantity after this fill
        /// </summary>
        public int RemainingQuantity { get; set; }

        /// <summary>
        /// Total quantity of the original order
        /// </summary>
        public int TotalQuantity { get; set; }

        /// <summary>
        /// Fill price for this partial fill
        /// </summary>
        public decimal FillPrice { get; set; }

        /// <summary>
        /// Average fill price across all fills so far
        /// </summary>
        public decimal AverageFillPrice { get; set; }

        /// <summary>
        /// Timestamp of this partial fill
        /// </summary>
        public DateTime FillTime { get; set; }

        /// <summary>
        /// Fill percentage (0-100)
        /// </summary>
        public double FillPercentage { get; set; }

        /// <summary>
        /// Whether this completes the order
        /// </summary>
        public bool IsComplete { get; set; }

        /// <summary>
        /// Constructor for PartialFillInfo
        /// </summary>
        public PartialFillInfo(
            string orderId,
            int filledQuantity,
            int remainingQuantity,
            int totalQuantity,
            decimal fillPrice,
            decimal averageFillPrice,
            DateTime fillTime)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");
            if (filledQuantity <= 0)
                throw new ArgumentException("FilledQuantity must be positive", "filledQuantity");
            if (totalQuantity <= 0)
                throw new ArgumentException("TotalQuantity must be positive", "totalQuantity");

            OrderId = orderId;
            FilledQuantity = filledQuantity;
            RemainingQuantity = remainingQuantity;
            TotalQuantity = totalQuantity;
            FillPrice = fillPrice;
            AverageFillPrice = averageFillPrice;
            FillTime = fillTime;
            FillPercentage = ((double)(totalQuantity - remainingQuantity) / (double)totalQuantity) * 100.0;
            IsComplete = remainingQuantity == 0;
        }
    }

    /// <summary>
    /// Strategy for handling partial fills
    /// </summary>
    public enum PartialFillStrategy
    {
        /// <summary>
        /// Allow partial fills and wait for complete fill
        /// </summary>
        AllowAndWait,

        /// <summary>
        /// Cancel remaining quantity after first partial fill
        /// </summary>
        CancelRemaining,

        /// <summary>
        /// Accept any partial fill as complete
        /// </summary>
        AcceptPartial,

        /// <summary>
        /// Reject the order if not filled immediately (FOK-like)
        /// </summary>
        AllOrNone
    }

    /// <summary>
    /// Configuration for partial fill handling
    /// </summary>
    public class PartialFillConfig
    {
        /// <summary>
        /// Strategy to use for partial fills
        /// </summary>
        public PartialFillStrategy Strategy { get; set; }

        /// <summary>
        /// Minimum fill percentage to accept (0-100)
        /// </summary>
        public double MinimumFillPercentage { get; set; }

        /// <summary>
        /// Maximum time to wait for complete fill (seconds)
        /// </summary>
        public int MaxWaitTimeSeconds { get; set; }

        /// <summary>
        /// Whether to retry remaining quantity with new order
        /// </summary>
        public bool RetryRemaining { get; set; }

        /// <summary>
        /// Constructor for PartialFillConfig
        /// </summary>
        public PartialFillConfig(
            PartialFillStrategy strategy,
            double minimumFillPercentage,
            int maxWaitTimeSeconds,
            bool retryRemaining)
        {
            Strategy = strategy;
            MinimumFillPercentage = minimumFillPercentage;
            MaxWaitTimeSeconds = maxWaitTimeSeconds;
            RetryRemaining = retryRemaining;
        }

        /// <summary>
        /// Default configuration - allow partial fills and wait
        /// </summary>
        public static PartialFillConfig Default
        {
            get
            {
                return new PartialFillConfig(
                    PartialFillStrategy.AllowAndWait,
                    0.0,  // Accept any fill percentage
                    300,  // Wait up to 5 minutes
                    false // Don't auto-retry
                );
            }
        }
    }

    /// <summary>
    /// Result of handling a partial fill
    /// </summary>
    public class PartialFillResult
    {
        /// <summary>
        /// Order ID
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Action taken
        /// </summary>
        public PartialFillAction Action { get; set; }

        /// <summary>
        /// Reason for the action
        /// </summary>
        public string Reason { get; set; }

        /// <summary>
        /// Whether the order is now complete
        /// </summary>
        public bool IsComplete { get; set; }

        /// <summary>
        /// New order ID if retry was attempted
        /// </summary>
        public string RetryOrderId { get; set; }

        /// <summary>
        /// Constructor for PartialFillResult
        /// </summary>
        public PartialFillResult(
            string orderId,
            PartialFillAction action,
            string reason,
            bool isComplete,
            string retryOrderId)
        {
            OrderId = orderId;
            Action = action;
            Reason = reason;
            IsComplete = isComplete;
            RetryOrderId = retryOrderId;
        }
    }

    /// <summary>
    /// Action taken when handling partial fill
    /// </summary>
    public enum PartialFillAction
    {
        /// <summary>
        /// Continue waiting for complete fill
        /// </summary>
        Wait,

        /// <summary>
        /// Cancel remaining quantity
        /// </summary>
        CancelRemaining,

        /// <summary>
        /// Accept partial fill as complete
        /// </summary>
        AcceptPartial,

        /// <summary>
        /// Retry remaining quantity with new order
        /// </summary>
        RetryRemaining,

        /// <summary>
        /// No action needed (order complete)
        /// </summary>
        None
    }

    #endregion

    #region Phase 3 - Advanced Order Types

    /// <summary>
    /// Limit order request with specific price
    /// </summary>
    public class LimitOrderRequest : OrderRequest
    {
        /// <summary>
        /// Limit price for the order
        /// </summary>
        public new decimal LimitPrice { get; set; }

        /// <summary>
        /// Constructor for LimitOrderRequest
        /// </summary>
        /// <param name="symbol">Trading symbol</param>
        /// <param name="side">Order side (Buy/Sell)</param>
        /// <param name="quantity">Order quantity</param>
        /// <param name="limitPrice">Limit price</param>
        /// <param name="tif">Time in force</param>
        public LimitOrderRequest(string symbol, OrderSide side, int quantity, decimal limitPrice, TimeInForce tif)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentNullException("symbol");
            if (quantity <= 0)
                throw new ArgumentException("Quantity must be positive", "quantity");
            if (limitPrice <= 0)
                throw new ArgumentException("LimitPrice must be positive", "limitPrice");

            Symbol = symbol;
            Side = side;
            Quantity = quantity;
            LimitPrice = limitPrice;
            TimeInForce = tif;
            Type = OrderType.Limit;
            ClientOrderId = Guid.NewGuid().ToString();
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Stop order request (stop market order)
    /// </summary>
    public class StopOrderRequest : OrderRequest
    {
        /// <summary>
        /// Stop price that triggers the order
        /// </summary>
        public new decimal StopPrice { get; set; }

        /// <summary>
        /// Constructor for StopOrderRequest
        /// </summary>
        /// <param name="symbol">Trading symbol</param>
        /// <param name="side">Order side (Buy/Sell)</param>
        /// <param name="quantity">Order quantity</param>
        /// <param name="stopPrice">Stop price</param>
        /// <param name="tif">Time in force</param>
        public StopOrderRequest(string symbol, OrderSide side, int quantity, decimal stopPrice, TimeInForce tif)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentNullException("symbol");
            if (quantity <= 0)
                throw new ArgumentException("Quantity must be positive", "quantity");
            if (stopPrice <= 0)
                throw new ArgumentException("StopPrice must be positive", "stopPrice");

            Symbol = symbol;
            Side = side;
            Quantity = quantity;
            StopPrice = stopPrice;
            TimeInForce = tif;
            Type = OrderType.StopMarket;
            ClientOrderId = Guid.NewGuid().ToString();
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Stop-limit order request
    /// </summary>
    public class StopLimitOrderRequest : OrderRequest
    {
        /// <summary>
        /// Stop price that triggers the order
        /// </summary>
        public new decimal StopPrice { get; set; }

        /// <summary>
        /// Limit price for the triggered order
        /// </summary>
        public new decimal LimitPrice { get; set; }

        /// <summary>
        /// Constructor for StopLimitOrderRequest
        /// </summary>
        /// <param name="symbol">Trading symbol</param>
        /// <param name="side">Order side (Buy/Sell)</param>
        /// <param name="quantity">Order quantity</param>
        /// <param name="stopPrice">Stop price</param>
        /// <param name="limitPrice">Limit price</param>
        /// <param name="tif">Time in force</param>
        public StopLimitOrderRequest(string symbol, OrderSide side, int quantity, decimal stopPrice, decimal limitPrice, TimeInForce tif)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentNullException("symbol");
            if (quantity <= 0)
                throw new ArgumentException("Quantity must be positive", "quantity");
            if (stopPrice <= 0)
                throw new ArgumentException("StopPrice must be positive", "stopPrice");
            if (limitPrice <= 0)
                throw new ArgumentException("LimitPrice must be positive", "limitPrice");

            Symbol = symbol;
            Side = side;
            Quantity = quantity;
            StopPrice = stopPrice;
            LimitPrice = limitPrice;
            TimeInForce = tif;
            Type = OrderType.StopLimit;
            ClientOrderId = Guid.NewGuid().ToString();
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Market-if-touched order request
    /// </summary>
    public class MITOrderRequest : OrderRequest
    {
        /// <summary>
        /// Trigger price for the MIT order
        /// </summary>
        public decimal TriggerPrice { get; set; }

        /// <summary>
        /// Constructor for MITOrderRequest
        /// </summary>
        /// <param name="symbol">Trading symbol</param>
        /// <param name="side">Order side (Buy/Sell)</param>
        /// <param name="quantity">Order quantity</param>
        /// <param name="triggerPrice">Trigger price</param>
        /// <param name="tif">Time in force</param>
        public MITOrderRequest(string symbol, OrderSide side, int quantity, decimal triggerPrice, TimeInForce tif)
        {
            if (string.IsNullOrEmpty(symbol))
                throw new ArgumentNullException("symbol");
            if (quantity <= 0)
                throw new ArgumentException("Quantity must be positive", "quantity");
            if (triggerPrice <= 0)
                throw new ArgumentException("TriggerPrice must be positive", "triggerPrice");

            Symbol = symbol;
            Side = side;
            Quantity = quantity;
            TriggerPrice = triggerPrice;
            TimeInForce = tif;
            Type = OrderType.Market; // MIT orders become market orders when triggered
            ClientOrderId = Guid.NewGuid().ToString();
            CreatedTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Trailing stop configuration
    /// </summary>
    public class TrailingStopConfig
    {
        /// <summary>
        /// Trailing amount in ticks
        /// </summary>
        public int TrailingTicks { get; set; }

        /// <summary>
        /// Trailing amount as percentage of current price
        /// </summary>
        public decimal? TrailingPercent { get; set; }

        /// <summary>
        /// Whether to trail by ATR or fixed amount
        /// </summary>
        public bool UseAtrTrail { get; set; }

        /// <summary>
        /// ATR multiplier for dynamic trailing
        /// </summary>
        public decimal AtrMultiplier { get; set; }

        /// <summary>
        /// Constructor for TrailingStopConfig
        /// </summary>
        /// <param name="trailingTicks">Trailing amount in ticks</param>
        /// <param name="useAtrTrail">Whether to use ATR-based trailing</param>
        /// <param name="atrMultiplier">ATR multiplier if using ATR trail</param>
        public TrailingStopConfig(int trailingTicks, bool useAtrTrail = false, decimal atrMultiplier = 2m)
        {
            if (trailingTicks <= 0)
                throw new ArgumentException("TrailingTicks must be positive", "trailingTicks");
            if (atrMultiplier <= 0)
                throw new ArgumentException("AtrMultiplier must be positive", "atrMultiplier");

            TrailingTicks = trailingTicks;
            UseAtrTrail = useAtrTrail;
            AtrMultiplier = atrMultiplier;
        }

        /// <summary>
        /// Constructor for percentage-based trailing stop
        /// </summary>
        /// <param name="trailingPercent">Trailing percentage</param>
        public TrailingStopConfig(decimal trailingPercent)
        {
            if (trailingPercent <= 0 || trailingPercent >= 100)
                throw new ArgumentException("TrailingPercent must be between 0 and 100", "trailingPercent");

            TrailingPercent = trailingPercent;
        }
    }

    /// <summary>
    /// Parameters for different order types
    /// </summary>
    public class OrderTypeParameters
    {
        /// <summary>
        /// For limit orders - the limit price
        /// </summary>
        public decimal? LimitPrice { get; set; }

        /// <summary>
        /// For stop orders - the stop price
        /// </summary>
        public decimal? StopPrice { get; set; }

        /// <summary>
        /// For trailing stops - the trailing configuration
        /// </summary>
        public TrailingStopConfig TrailingConfig { get; set; }

        /// <summary>
        /// For iceberg orders - the displayed quantity
        /// </summary>
        public int? DisplayQty { get; set; }

        /// <summary>
        /// For algo orders - additional parameters
        /// </summary>
        public Dictionary<string, object> AdditionalParams { get; set; }

        /// <summary>
        /// Constructor for OrderTypeParameters
        /// </summary>
        public OrderTypeParameters()
        {
            AdditionalParams = new Dictionary<string, object>();
        }
    }

    #endregion
}
