using System;
using System.Collections.Generic;

namespace NT8.Core.OMS
{
    /// <summary>
    /// Formal state machine for order lifecycle management
    /// Validates and tracks state transitions for orders
    /// </summary>
    public class OrderStateMachine
    {
        private readonly object _lock = new object();
        private readonly Dictionary<string, StateTransition> _validTransitions;
        private readonly Dictionary<string, List<OrderState>> _allowedTransitions;

        /// <summary>
        /// Constructor for OrderStateMachine
        /// </summary>
        public OrderStateMachine()
        {
            _validTransitions = new Dictionary<string, StateTransition>();
            _allowedTransitions = new Dictionary<string, List<OrderState>>();
            InitializeTransitionRules();
        }

        /// <summary>
        /// Initialize valid state transition rules
        /// </summary>
        private void InitializeTransitionRules()
        {
            // Define allowed transitions for each state
            _allowedTransitions.Add(
                OrderState.Pending.ToString(),
                new List<OrderState> { OrderState.Submitted, OrderState.Rejected, OrderState.Cancelled }
            );

            _allowedTransitions.Add(
                OrderState.Submitted.ToString(),
                new List<OrderState> { OrderState.Accepted, OrderState.Rejected, OrderState.Cancelled }
            );

            _allowedTransitions.Add(
                OrderState.Accepted.ToString(),
                new List<OrderState> { OrderState.Working, OrderState.Rejected, OrderState.Cancelled }
            );

            _allowedTransitions.Add(
                OrderState.Working.ToString(),
                new List<OrderState> { OrderState.PartiallyFilled, OrderState.Filled, OrderState.Cancelled, OrderState.Expired }
            );

            _allowedTransitions.Add(
                OrderState.PartiallyFilled.ToString(),
                new List<OrderState> { OrderState.Filled, OrderState.Cancelled, OrderState.Expired }
            );

            // Terminal states (no transitions allowed)
            _allowedTransitions.Add(OrderState.Filled.ToString(), new List<OrderState>());
            _allowedTransitions.Add(OrderState.Cancelled.ToString(), new List<OrderState>());
            _allowedTransitions.Add(OrderState.Rejected.ToString(), new List<OrderState>());
            _allowedTransitions.Add(OrderState.Expired.ToString(), new List<OrderState>());
        }

        /// <summary>
        /// Validate whether a state transition is allowed
        /// </summary>
        /// <param name="orderId">Order ID for tracking</param>
        /// <param name="currentState">Current order state</param>
        /// <param name="newState">Proposed new state</param>
        /// <returns>Validation result</returns>
        public StateTransitionResult ValidateTransition(string orderId, OrderState currentState, OrderState newState)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            lock (_lock)
            {
                // Same state is always allowed (idempotent)
                if (currentState == newState)
                {
                    return new StateTransitionResult(
                        true,
                        string.Format("Order {0} already in state {1}", orderId, currentState),
                        currentState,
                        newState
                    );
                }

                // Check if transition is defined
                var currentKey = currentState.ToString();
                if (!_allowedTransitions.ContainsKey(currentKey))
                {
                    return new StateTransitionResult(
                        false,
                        string.Format("Unknown current state: {0}", currentState),
                        currentState,
                        newState
                    );
                }

                var allowedStates = _allowedTransitions[currentKey];

                // Check if transition is allowed
                if (!allowedStates.Contains(newState))
                {
                    return new StateTransitionResult(
                        false,
                        string.Format("Invalid transition from {0} to {1}", currentState, newState),
                        currentState,
                        newState
                    );
                }

                // Valid transition
                return new StateTransitionResult(
                    true,
                    string.Format("Valid transition from {0} to {1}", currentState, newState),
                    currentState,
                    newState
                );
            }
        }

        /// <summary>
        /// Record a state transition (for audit/history)
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="fromState">Previous state</param>
        /// <param name="toState">New state</param>
        /// <param name="reason">Reason for transition</param>
        public void RecordTransition(string orderId, OrderState fromState, OrderState toState, string reason)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            lock (_lock)
            {
                var key = string.Format("{0}_{1}", orderId, DateTime.UtcNow.Ticks);
                var transition = new StateTransition(
                    orderId,
                    fromState,
                    toState,
                    reason,
                    DateTime.UtcNow
                );

                _validTransitions[key] = transition;
            }
        }

        /// <summary>
        /// Get all recorded transitions for an order
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <returns>List of transitions</returns>
        public List<StateTransition> GetOrderHistory(string orderId)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            var history = new List<StateTransition>();

            lock (_lock)
            {
                foreach (var kvp in _validTransitions)
                {
                    if (kvp.Value.OrderId == orderId)
                    {
                        history.Add(kvp.Value);
                    }
                }
            }

            return history;
        }

        /// <summary>
        /// Check if a state is terminal (no further transitions allowed)
        /// </summary>
        /// <param name="state">State to check</param>
        /// <returns>True if terminal state</returns>
        public bool IsTerminalState(OrderState state)
        {
            lock (_lock)
            {
                var key = state.ToString();
                if (!_allowedTransitions.ContainsKey(key))
                    return false;

                return _allowedTransitions[key].Count == 0;
            }
        }

        /// <summary>
        /// Get allowed next states for a given current state
        /// </summary>
        /// <param name="currentState">Current state</param>
        /// <returns>List of allowed next states</returns>
        public List<OrderState> GetAllowedNextStates(OrderState currentState)
        {
            lock (_lock)
            {
                var key = currentState.ToString();
                if (!_allowedTransitions.ContainsKey(key))
                    return new List<OrderState>();

                return new List<OrderState>(_allowedTransitions[key]);
            }
        }

        /// <summary>
        /// Clear recorded history (for testing or reset)
        /// </summary>
        public void ClearHistory()
        {
            lock (_lock)
            {
                _validTransitions.Clear();
            }
        }
    }

    /// <summary>
    /// Represents a state transition event
    /// </summary>
    public class StateTransition
    {
        /// <summary>
        /// Order ID
        /// </summary>
        public string OrderId { get; private set; }

        /// <summary>
        /// Previous state
        /// </summary>
        public OrderState FromState { get; private set; }

        /// <summary>
        /// New state
        /// </summary>
        public OrderState ToState { get; private set; }

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

        /// <summary>
        /// Timestamp of transition
        /// </summary>
        public DateTime TransitionTime { get; private set; }

        /// <summary>
        /// Constructor for StateTransition
        /// </summary>
        public StateTransition(
            string orderId,
            OrderState fromState,
            OrderState toState,
            string reason,
            DateTime transitionTime)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            OrderId = orderId;
            FromState = fromState;
            ToState = toState;
            Reason = reason;
            TransitionTime = transitionTime;
        }
    }

    /// <summary>
    /// Result of a state transition validation
    /// </summary>
    public class StateTransitionResult
    {
        /// <summary>
        /// Whether the transition is valid
        /// </summary>
        public bool IsValid { get; private set; }

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

        /// <summary>
        /// Current state
        /// </summary>
        public OrderState CurrentState { get; private set; }

        /// <summary>
        /// Proposed new state
        /// </summary>
        public OrderState ProposedState { get; private set; }

        /// <summary>
        /// Constructor for StateTransitionResult
        /// </summary>
        public StateTransitionResult(
            bool isValid,
            string message,
            OrderState currentState,
            OrderState proposedState)
        {
            IsValid = isValid;
            Message = message;
            CurrentState = currentState;
            ProposedState = proposedState;
        }
    }
}
