using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;

namespace NT8.Core.Execution
{
    /// <summary>
    /// Detects duplicate order submissions to prevent accidental double entries
    /// </summary>
    public class DuplicateOrderDetector
    {
        private readonly ILogger _logger;
        private readonly object _lock = new object();

        // Store order intents with timestamps
        private readonly Dictionary<string, OrderIntentRecord> _recentIntents;

        // Default time window for duplicate detection (5 seconds)
        private readonly TimeSpan _duplicateWindow;

        /// <summary>
        /// Constructor for DuplicateOrderDetector
        /// </summary>
        /// <param name="logger">Logger instance</param>
        /// <param name="duplicateWindow">Time window for duplicate detection</param>
        public DuplicateOrderDetector(ILogger<DuplicateOrderDetector> logger, TimeSpan? duplicateWindow = null)
        {
            if (logger == null)
                throw new ArgumentNullException("logger");

            _logger = logger;
            _duplicateWindow = duplicateWindow ?? TimeSpan.FromSeconds(5);
            _recentIntents = new Dictionary<string, OrderIntentRecord>();
        }

        /// <summary>
        /// Checks if an order is a duplicate of a recent order
        /// </summary>
        /// <param name="request">Order request to check</param>
        /// <returns>True if order is a duplicate, false otherwise</returns>
        public bool IsDuplicateOrder(OMS.OrderRequest request)
        {
            if (request == null)
                throw new ArgumentNullException("request");

            try
            {
                lock (_lock)
                {
                    // Clean up old intents first
                    ClearOldIntents(_duplicateWindow);

                    // Create a key based on symbol, side, and quantity
                    var key = CreateOrderKey(request);

                    // Check if we have a recent order with same characteristics
                    if (_recentIntents.ContainsKey(key))
                    {
                        var record = _recentIntents[key];
                        var timeDiff = DateTime.UtcNow - record.Timestamp;

                        // If the time difference is within our window, it's a duplicate
                        if (timeDiff <= _duplicateWindow)
                        {
                            _logger.LogDebug("Duplicate order detected: {Key} at {TimeDiff} ago", key, timeDiff);
                            return true;
                        }
                    }

                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to check for duplicate order: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Records an order intent for duplicate checking
        /// </summary>
        /// <param name="request">Order request to record</param>
        public void RecordOrderIntent(OMS.OrderRequest request)
        {
            if (request == null)
                throw new ArgumentNullException("request");

            try
            {
                lock (_lock)
                {
                    var key = CreateOrderKey(request);
                    var record = new OrderIntentRecord
                    {
                        OrderRequest = request,
                        Timestamp = DateTime.UtcNow
                    };

                    _recentIntents[key] = record;

                    _logger.LogDebug("Recorded order intent: {Key}", key);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to record order intent: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Clears old order intents that are beyond the duplicate window
        /// </summary>
        /// <param name="maxAge">Maximum age of intents to keep</param>
        public void ClearOldIntents(TimeSpan maxAge)
        {
            try
            {
                lock (_lock)
                {
                    var cutoffTime = DateTime.UtcNow - maxAge;
                    var keysToRemove = _recentIntents
                        .Where(kvp => kvp.Value.Timestamp < cutoffTime)
                        .Select(kvp => kvp.Key)
                        .ToList();

                    foreach (var key in keysToRemove)
                    {
                        _recentIntents.Remove(key);
                    }

                    if (keysToRemove.Any())
                    {
                        _logger.LogDebug("Cleared {Count} old order intents", keysToRemove.Count);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to clear old order intents: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Creates a unique key for an order based on symbol, side, and quantity
        /// </summary>
        /// <param name="request">Order request to create key for</param>
        /// <returns>Unique key for the order</returns>
        private string CreateOrderKey(OMS.OrderRequest request)
        {
            if (request == null)
                return string.Empty;

            var symbol = request.Symbol != null ? request.Symbol.ToLower() : string.Empty;
            return string.Format("{0}_{1}_{2}",
                symbol,
                request.Side,
                request.Quantity);
        }

        /// <summary>
        /// Gets the count of recent order intents
        /// </summary>
        /// <returns>Number of recent order intents</returns>
        public int GetRecentIntentCount()
        {
            try
            {
                lock (_lock)
                {
                    return _recentIntents.Count;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to get recent intent count: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Clears all recorded order intents
        /// </summary>
        public void ClearAllIntents()
        {
            try
            {
                lock (_lock)
                {
                    _recentIntents.Clear();
                    _logger.LogDebug("Cleared all order intents");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to clear all order intents: {Message}", ex.Message);
                throw;
            }
        }
    }

    /// <summary>
    /// Record of an order intent with timestamp
    /// </summary>
    internal class OrderIntentRecord
    {
        /// <summary>
        /// The order request that was intended
        /// </summary>
        public OMS.OrderRequest OrderRequest { get; set; }

        /// <summary>
        /// When the intent was recorded
        /// </summary>
        public DateTime Timestamp { get; set; }
    }
}
