using System.Collections.Generic;
using System.Threading.Tasks;
using PolyTraderSharp.Models;
using PolyTraderSharp.Services;

namespace PolyTrader.Tests.Fakes
{
    /// <summary>
    /// In-Memory-Stub für <see cref="IClobClient"/>. Zeichnet Aufrufe auf und liefert steuerbare
    /// Antworten, damit die Service-Interaktionen (SELL-Leiter, Startup-Reconciliation) ohne echten
    /// CLOB integrationstestbar sind. Bewusst simpel und synchron (Task.FromResult).
    /// </summary>
    public sealed class FakeClobClient : IClobClient
    {
        public sealed record PlacedOrder(string TokenId, string Side, decimal Usdc, decimal Price, string OrderType);

        // Aufzeichnungen
        public List<PlacedOrder> Placed { get; } = new();
        public List<string> CanceledOrderIds { get; } = new();
        public List<(string AssetId, decimal NewPrice, string Side)> ConflictCancels { get; } = new();

        // Steuerbare Antworten
        /// <summary>Ergebnis von PlaceOrderAsync (Default "OK"). Queue hat Vorrang, sonst dieser Wert.</summary>
        public string PlaceResult { get; set; } = "OK";
        public Queue<string> PlaceResults { get; } = new();
        public bool CancelResult { get; set; } = true;

        /// <summary>Offene Orders je Asset, die GetOpenOrdersAsync(assetId) zurückgibt.</summary>
        public Dictionary<string, List<(string Id, string Side, decimal Price)>> OpenOrdersByAsset { get; } = new();

        /// <summary>Alle offenen Orders des Accounts, die GetOpenOrdersAsync() ohne assetId zurückgibt (K2).</summary>
        public List<(string Id, string Side, decimal Price)> AllOpenOrders { get; } = new();

        public Task<string> PlaceOrderAsync(
            AccountState account, string tokenId, string sideStr, decimal investAmountUsd, decimal limitPrice,
            string orderType = "FOK", bool debugPayloadLog = false, bool isNegRisk = false, int actualFeeBps = 0,
            decimal? overrideTickSize = null, int? overrideMakerDecimals = null, int? overrideTakerDecimals = null)
        {
            Placed.Add(new PlacedOrder(tokenId, sideStr, investAmountUsd, limitPrice, orderType));
            string result = PlaceResults.Count > 0 ? PlaceResults.Dequeue() : PlaceResult;
            return Task.FromResult(result);
        }

        public Task CancelConflictingOrdersAsync(AccountState acc, string assetId, decimal newPrice, string sideStr)
        {
            ConflictCancels.Add((assetId, newPrice, sideStr));
            return Task.CompletedTask;
        }

        public Task<List<(string Id, string Side, decimal Price)>> GetOpenOrdersAsync(AccountState acc, string assetId = "")
        {
            if (string.IsNullOrEmpty(assetId))
                return Task.FromResult(new List<(string, string, decimal)>(AllOpenOrders));
            if (OpenOrdersByAsset.TryGetValue(assetId, out var list))
                return Task.FromResult(new List<(string, string, decimal)>(list));
            return Task.FromResult(new List<(string, string, decimal)>());
        }

        public Task<bool> CancelOrderAsync(AccountState acc, string orderId)
        {
            CanceledOrderIds.Add(orderId);
            return Task.FromResult(CancelResult);
        }
    }
}
