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

namespace NT8.Core.Execution
{
    /// <summary>
    /// Manages multiple profit targets for scaling out of positions
    /// </summary>
    public class MultiLevelTargetManager
    {
        private readonly ILogger _logger;
        private readonly object _lock = new object();

        // Store target information for each order
        private readonly Dictionary<string, MultiLevelTargetInfo> _multiLevelTargets;

        /// <summary>
        /// Constructor for MultiLevelTargetManager
        /// </summary>
        /// <param name="logger">Logger instance</param>
        public MultiLevelTargetManager(ILogger<MultiLevelTargetManager> logger)
        {
            if (logger == null)
                throw new ArgumentNullException("logger");

            _logger = logger;
            _multiLevelTargets = new Dictionary<string, MultiLevelTargetInfo>();
        }

        /// <summary>
        /// Sets multiple profit targets for an order
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="targets">Multi-level target configuration</param>
        public void SetTargets(string orderId, MultiLevelTargets targets)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");
            if (targets == null)
                throw new ArgumentNullException("targets");

            try
            {
                lock (_lock)
                {
                    var targetInfo = new MultiLevelTargetInfo
                    {
                        OrderId = orderId,
                        Targets = targets,
                        CompletedTargets = new HashSet<int>(),
                        Active = true,
                        StartTime = DateTime.UtcNow
                    };

                    _multiLevelTargets[orderId] = targetInfo;

                    _logger.LogDebug("Set multi-level targets for {OrderId}: TP1={TP1}({TP1C} contracts), TP2={TP2}({TP2C} contracts), TP3={TP3}({TP3C} contracts)",
                        orderId,
                        targets.TP1Ticks, targets.TP1Contracts,
                        targets.TP2Ticks ?? 0, targets.TP2Contracts ?? 0,
                        targets.TP3Ticks ?? 0, targets.TP3Contracts ?? 0);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to set targets for {OrderId}: {Message}", orderId, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Processes a target hit and determines next action
        /// </summary>
        /// <param name="orderId">Order ID</param>
        /// <param name="targetLevel">Target level that was hit (1, 2, or 3)</param>
        /// <param name="hitPrice">Price at which target was hit</param>
        /// <returns>Action to take after target hit</returns>
        public TargetActionResult OnTargetHit(string orderId, int targetLevel, decimal hitPrice)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            try
            {
                lock (_lock)
                {
                    if (!_multiLevelTargets.ContainsKey(orderId))
                    {
                        _logger.LogWarning("No multi-level targets found for {OrderId}", orderId);
                        return new TargetActionResult(TargetAction.NoAction, "No targets configured", 0);
                    }

                    var targetInfo = _multiLevelTargets[orderId];
                    if (!targetInfo.Active || targetInfo.CompletedTargets.Contains(targetLevel))
                    {
                        return new TargetActionResult(TargetAction.NoAction, "Target already completed or inactive", 0);
                    }

                    // Calculate contracts to close based on target level
                    int contractsToClose = 0;
                    string targetDescription = "";

                    switch (targetLevel)
                    {
                        case 1:
                            contractsToClose = targetInfo.Targets.TP1Contracts;
                            targetDescription = String.Format("TP1 at {0} ticks", targetInfo.Targets.TP1Ticks);
                            break;
                        case 2:
                            if (targetInfo.Targets.TP2Contracts.HasValue)
                            {
                                contractsToClose = targetInfo.Targets.TP2Contracts.Value;
                                targetDescription = String.Format("TP2 at {0} ticks", targetInfo.Targets.TP2Ticks);
                            }
                            else
                            {
                                return new TargetActionResult(TargetAction.NoAction, "TP2 not configured", 0);
                            }
                            break;
                        case 3:
                            if (targetInfo.Targets.TP3Contracts.HasValue)
                            {
                                contractsToClose = targetInfo.Targets.TP3Contracts.Value;
                                targetDescription = String.Format("TP3 at {0} ticks", targetInfo.Targets.TP3Ticks);
                            }
                            else
                            {
                                return new TargetActionResult(TargetAction.NoAction, "TP3 not configured", 0);
                            }
                            break;
                        default:
                            return new TargetActionResult(TargetAction.NoAction, "Invalid target level", 0);
                    }

                    // Mark this target as completed
                    targetInfo.CompletedTargets.Add(targetLevel);

                    // Determine next action
                    TargetAction action;
                    string message;

                    // Check if all configured targets have been hit
                    var allConfiguredTargets = new List<int> { 1 };
                    if (targetInfo.Targets.TP2Ticks.HasValue) allConfiguredTargets.Add(2);
                    if (targetInfo.Targets.TP3Ticks.HasValue) allConfiguredTargets.Add(3);

                    if (targetInfo.CompletedTargets.Count == allConfiguredTargets.Count)
                    {
                        // All targets hit - position should be fully closed
                        action = TargetAction.ClosePosition;
                        message = String.Format("All targets hit - {0} closed {1} contracts", targetDescription, contractsToClose);
                    }
                    else
                    {
                        // More targets remain - partial close
                        action = TargetAction.PartialClose;
                        message = String.Format("{0} hit - closing {1} contracts", targetDescription, contractsToClose);
                    }

                    _logger.LogDebug("Target hit for {OrderId}: {Message}", orderId, message);

                    return new TargetActionResult(action, message, contractsToClose);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to process target hit for {OrderId}: {Message}", orderId, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Calculates the number of contracts to close at a target level
        /// </summary>
        /// <param name="targetLevel">Target level (1, 2, or 3)</param>
        /// <returns>Number of contracts to close</returns>
        public int CalculateContractsToClose(int targetLevel)
        {
            try
            {
                // This method would typically be called as part of a larger calculation
                // For now, returning 0 as the actual number depends on the order details
                // which would be stored in the MultiLevelTargetInfo
                return 0;
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to calculate contracts to close for target {Level}: {Message}", targetLevel, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Checks if a target level should advance stop management
        /// </summary>
        /// <param name="targetLevel">Target level that was hit</param>
        /// <returns>True if stops should be advanced, false otherwise</returns>
        public bool ShouldAdvanceStop(int targetLevel)
        {
            try
            {
                // Typically, advancing stops happens after certain targets are hit
                // For example, after TP1, move stops to breakeven
                // After TP2, start trailing stops
                switch (targetLevel)
                {
                    case 1:
                        // After first target, consider moving stops to breakeven
                        return true;
                    case 2:
                        // After second target, consider tightening trailing stops
                        return true;
                    case 3:
                        // After third target, position is likely closing
                        return false;
                    default:
                        return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to determine stop advancement for target {Level}: {Message}", targetLevel, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Gets the target status for an order
        /// </summary>
        /// <param name="orderId">Order ID to get status for</param>
        /// <returns>Target status information</returns>
        public TargetStatus GetTargetStatus(string orderId)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            try
            {
                lock (_lock)
                {
                    if (_multiLevelTargets.ContainsKey(orderId))
                    {
                        var targetInfo = _multiLevelTargets[orderId];

                        var remainingTargets = new List<int>();
                        if (!targetInfo.CompletedTargets.Contains(1)) remainingTargets.Add(1);
                        if (targetInfo.Targets.TP2Ticks.HasValue && !targetInfo.CompletedTargets.Contains(2)) remainingTargets.Add(2);
                        if (targetInfo.Targets.TP3Ticks.HasValue && !targetInfo.CompletedTargets.Contains(3)) remainingTargets.Add(3);

                        return new TargetStatus
                        {
                            OrderId = orderId,
                            Active = targetInfo.Active,
                            CompletedTargets = new HashSet<int>(targetInfo.CompletedTargets),
                            RemainingTargets = remainingTargets,
                            TotalTargets = targetInfo.Targets.TP3Ticks.HasValue ? 3 :
                                          targetInfo.Targets.TP2Ticks.HasValue ? 2 : 1
                        };
                    }

                    return new TargetStatus
                    {
                        OrderId = orderId,
                        Active = false,
                        CompletedTargets = new HashSet<int>(),
                        RemainingTargets = new List<int>(),
                        TotalTargets = 0
                    };
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to get target status for {OrderId}: {Message}", orderId, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Deactivates multi-level targeting for an order
        /// </summary>
        /// <param name="orderId">Order ID to deactivate</param>
        public void DeactivateTargets(string orderId)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            try
            {
                lock (_lock)
                {
                    if (_multiLevelTargets.ContainsKey(orderId))
                    {
                        _multiLevelTargets[orderId].Active = false;
                        _logger.LogDebug("Deactivated multi-level targets for {OrderId}", orderId);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to deactivate targets for {OrderId}: {Message}", orderId, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Removes multi-level target tracking for an order
        /// </summary>
        /// <param name="orderId">Order ID to remove</param>
        public void RemoveTargets(string orderId)
        {
            if (string.IsNullOrEmpty(orderId))
                throw new ArgumentNullException("orderId");

            try
            {
                lock (_lock)
                {
                    if (_multiLevelTargets.ContainsKey(orderId))
                    {
                        _multiLevelTargets.Remove(orderId);
                        _logger.LogDebug("Removed multi-level target tracking for {OrderId}", orderId);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to remove targets for {OrderId}: {Message}", orderId, ex.Message);
                throw;
            }
        }
    }

    /// <summary>
    /// Information about multi-level targets for an order
    /// </summary>
    internal class MultiLevelTargetInfo
    {
        /// <summary>
        /// Order ID this targets are for
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Target configuration
        /// </summary>
        public MultiLevelTargets Targets { get; set; }

        /// <summary>
        /// Set of completed target levels
        /// </summary>
        public HashSet<int> CompletedTargets { get; set; }

        /// <summary>
        /// Whether target tracking is active
        /// </summary>
        public bool Active { get; set; }

        /// <summary>
        /// When target tracking was started
        /// </summary>
        public DateTime StartTime { get; set; }
    }

    /// <summary>
    /// Result of target hit processing
    /// </summary>
    public class TargetActionResult
    {
        /// <summary>
        /// Action to take
        /// </summary>
        public TargetAction Action { get; set; }

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

        /// <summary>
        /// Number of contracts to close (for partial closes)
        /// </summary>
        public int ContractsToClose { get; set; }

        /// <summary>
        /// Constructor for TargetActionResult
        /// </summary>
        /// <param name="action">Action to take</param>
        /// <param name="message">Description message</param>
        /// <param name="contractsToClose">Contracts to close</param>
        public TargetActionResult(TargetAction action, string message, int contractsToClose)
        {
            Action = action;
            Message = message;
            ContractsToClose = contractsToClose;
        }
    }

    /// <summary>
    /// Status of multi-level targets
    /// </summary>
    public class TargetStatus
    {
        /// <summary>
        /// Order ID
        /// </summary>
        public string OrderId { get; set; }

        /// <summary>
        /// Whether target tracking is active
        /// </summary>
        public bool Active { get; set; }

        /// <summary>
        /// Completed target levels
        /// </summary>
        public HashSet<int> CompletedTargets { get; set; }

        /// <summary>
        /// Remaining target levels
        /// </summary>
        public List<int> RemainingTargets { get; set; }

        /// <summary>
        /// Total number of configured targets
        /// </summary>
        public int TotalTargets { get; set; }
    }

    /// <summary>
    /// Action to take when a target is hit
    /// </summary>
    public enum TargetAction
    {
        /// <summary>
        /// No action needed
        /// </summary>
        NoAction = 0,

        /// <summary>
        /// Partially close the position
        /// </summary>
        PartialClose = 1,

        /// <summary>
        /// Close the entire position
        /// </summary>
        ClosePosition = 2,

        /// <summary>
        /// Move stops to breakeven
        /// </summary>
        MoveToBreakeven = 3,

        /// <summary>
        /// Start trailing stops
        /// </summary>
        StartTrailing = 4
    }
}
