using System;
using PolyTrader.Core.Notifications;
using PolyTrader.Modules.CopyTrading.Logic;
using PolyTrader.Modules.CopyTrading.Persistence;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using PolyTraderSharp.Models;

namespace PolyTraderSharp.Services
{
    public class MasterTraderAnalyticsJob : BackgroundService
    {
        private readonly TradingState _state;
        private readonly CopyTradingState _copyState;
        private readonly TerminalLogger _logger;
        private readonly IMasterTraderHistoryRepository _historyRepo;
        private readonly ITrackedTraderRepository _traderRepo;
        private readonly ICopyTradeLogRepository _tradeLog;
        private readonly INotificationSink _notify;
        private readonly JobStatusRow _jobStatus;
        private readonly PolymarketApiService _api;

        public MasterTraderAnalyticsJob(TradingState state, CopyTradingState copyState, TerminalLogger logger, IMasterTraderHistoryRepository historyRepo, ITrackedTraderRepository traderRepo, ICopyTradeLogRepository tradeLog, INotificationSink notify, JobManager jobManager, PolymarketApiService api)
        {
            _state = state;
            _copyState = copyState;
            _logger = logger;
            _historyRepo = historyRepo;
            _traderRepo = traderRepo;
            _tradeLog = tradeLog;
            _notify = notify;
            _api = api;

            _jobStatus = new JobStatusRow
            {
                JobName = "MasterTrader History",
                Description = "Überwacht die Performance aller Master-Trader (P&L, Winrate 7D).",
                StatusText = "Pending Initial Delay..."
            };

            _jobStatus.ManualTriggerAction = async () => 
            {
                _jobStatus.StatusText = "Running (Manual)...";
                await RunHistoryAnalyticsAsync();
                _jobStatus.StatusText = "Idle";
                _jobStatus.LastRun = DateTime.Now;
            };

            jobManager.RegisterJob(_jobStatus);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Delay(TimeSpan.FromSeconds(20), stoppingToken); // Start after other jobs

            // M5: Auto-Pause reagiert stündlich (Light-Check aus UNSEREN Trades), die schwere
            // Master-History-Analyse (flakige Data-API) läuft weiter nur alle 12h. Beide schließen
            // sich pro Tick aus – RunHistoryAnalyticsAsync ruft den Copy-Score selbst auf, also
            // kein Doppellauf.
            DateTime lastHeavyRun = DateTime.MinValue;
            while (!stoppingToken.IsCancellationRequested)
            {
                if (_jobStatus.IsEnabled)
                {
                    try
                    {
                        if ((DateTime.UtcNow - lastHeavyRun) >= TimeSpan.FromHours(12))
                        {
                            _jobStatus.StatusText = "Running (History + Auto-Pause)...";
                            await RunHistoryAnalyticsAsync();   // enthält Copy-Score + Auto-Pause
                            lastHeavyRun = DateTime.UtcNow;
                        }
                        else
                        {
                            _jobStatus.StatusText = "Running (Auto-Pause-Check)...";
                            await UpdateCopyScoresAndAutoPauseAsync();   // stündlicher Light-Check
                        }
                        _jobStatus.LastRun = DateTime.Now;
                    }
                    catch (Exception ex)
                    {
                        _logger.Error($"Error in MasterTraderAnalyticsJob: {ex.Message}");
                        _jobStatus.StatusText = "Error!";
                    }
                    finally
                    {
                        if (_jobStatus.StatusText != "Error!") _jobStatus.StatusText = "Idle";
                    }
                }
                else
                {
                    _jobStatus.StatusText = "Paused";
                }

                // Light-Check-Kadenz: stündlich (Auto-Pause reagiert schneller).
                _jobStatus.NextRun = DateTime.Now.AddHours(1);
                await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
            }
        }

        public async Task RunHistoryAnalyticsAsync()
        {
            try
            {
                _logger.Info("🔄 Starte Master-Trader Historien-Download und Performance-Analyse...");
                
                _historyRepo.EnsureIndexes();

                DateTime cutoff7Days = DateTime.UtcNow.AddDays(-7);
                var tradersToAnalyze = _copyState.Traders.Values.Where(t => t.IsActive && !string.IsNullOrEmpty(t.WalletAddress)).ToList();

                foreach (var trader in tradersToAnalyze)
                {
                    try
                    {
                        // 1. Fetch History from Data API (100 is usually enough for 7 days)
                        var closedPositions = await _api.SyncClosedPositionsAsync(trader.WalletAddress, 200);
                        if (closedPositions.Count == 0)
                        {
                            continue; // Might be deleted or no history
                        }

                        int inserted = 0;
                        foreach (var cp in closedPositions)
                        {
                            // parse timestamp
                            DateTime closedTs = DateTime.UnixEpoch;
                            if (cp.TryGetProperty("timestamp", out var tsProp))
                            {
                                if (tsProp.ValueKind == JsonValueKind.Number)
                                {
                                    long tsRaw = tsProp.GetInt64();
                                    // if it's 13 digits (ms) vs 10 digits (s)
                                    if (tsRaw > 1000000000000) closedTs = DateTimeOffset.FromUnixTimeMilliseconds(tsRaw).UtcDateTime;
                                    else closedTs = DateTimeOffset.FromUnixTimeSeconds(tsRaw).UtcDateTime;
                                }
                                else if (tsProp.ValueKind == JsonValueKind.String
                                    && long.TryParse(tsProp.GetString(), System.Globalization.NumberStyles.Integer,
                                        System.Globalization.CultureInfo.InvariantCulture, out long tsStrRaw))
                                {
                                    if (tsStrRaw > 1000000000000) closedTs = DateTimeOffset.FromUnixTimeMilliseconds(tsStrRaw).UtcDateTime;
                                    else closedTs = DateTimeOffset.FromUnixTimeSeconds(tsStrRaw).UtcDateTime;
                                }
                            }

                            // If trade is older than 14 days, ignore parsing to save DB space
                            if (closedTs < DateTime.UtcNow.AddDays(-14)) continue;

                            string tokenId = cp.TryGetProperty("asset", out var aProp) ? aProp.GetString() ?? "" : "";
                            
                            decimal pnl = 0m;
                            if (cp.TryGetProperty("realizedPnl", out var pProp))
                            {
                                if (pProp.ValueKind == JsonValueKind.Number) pnl = pProp.GetDecimal();
                                else if (pProp.ValueKind == JsonValueKind.String && decimal.TryParse(pProp.GetString(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out decimal nPnl))
                                {
                                    pnl = nPnl;
                                }
                            }

                            // We can approximate uniqueness with TokenId & exact Time (+- 2 seconds)
                            DateTime windowStart = closedTs.AddSeconds(-2);
                            DateTime windowEnd = closedTs.AddSeconds(2);

                            bool exists = _historyRepo.Exists(trader.Id, tokenId, windowStart, windowEnd);
                            if (!exists)
                            {
                                var record = new MasterTraderHistoryRecord
                                {
                                    TraderId = trader.Id,
                                    TokenId = tokenId,
                                    ClosedAt = closedTs,
                                    RealizedPnl = pnl
                                };
                                _historyRepo.Insert(record);
                                inserted++;
                            }
                        }

                        // Sleep to respect 10/s limits or general rate limits
                        await Task.Delay(200);

                        // 2. Calculate Stats from DB
                        var last7DaysTrades = _historyRepo.GetByTraderSince(trader.Id, cutoff7Days);
                        
                        trader.TotalTrades = last7DaysTrades.Count;
                        trader.TotalPnl = (double)last7DaysTrades.Sum(x => x.RealizedPnl);
                        
                        // Treat positive PnL as win
                        trader.WinningTrades = last7DaysTrades.Count(x => x.RealizedPnl > 0);
                        trader.Winrate30t = trader.TotalTrades > 0 ? Math.Round(((double)trader.WinningTrades / trader.TotalTrades) * 100, 2) : 0;

                        // Save updated trader to DB so UI updates
                        _traderRepo.Update(trader);
                        
                        if (inserted > 0 && trader.TotalTrades > 0)
                        {
                            _logger.Info($"📊 [MasterTrader: {trader.DisplayName}] - {inserted} neue Trades geladen. 7D: {trader.TotalTrades} Trades | PnL: ${trader.TotalPnl:F2} | Winrate: {trader.Winrate30t}%");
                        }
                    }
                    catch (Exception exInner)
                    {
                        _logger.Error($"Error processing history for MasterTrader {trader.DisplayName}: {exInner}");
                    }
                }

                _logger.Info("✅ Master-Trader Historien-Analyse abgeschlossen.");

                // Phase 3: Copy-Score + Auto-Pause – entkoppelt von der (flakigen) Master-History-API,
                // da aus UNSEREN geschlossenen Trades berechnet.
                await UpdateCopyScoresAndAutoPauseAsync();
            }
            catch (Exception ex)
            {
                _logger.Error($"MasterTraderAnalyticsJob Exception: {ex}");
            }
        }

        /// <summary>
        /// Phase 3.1/3.3 + M5: Berechnet je Master den Copy-Score (letzte 30 Tage aus unseren
        /// geschlossenen Copy-Trades). Die Anzeige-Spalten zeigen Live-Kennzahlen, sobald es
        /// Live-Trades gibt, sonst Demo-Kennzahlen – damit die Demo-Validierungsphase nicht blind ist.
        /// Die HARTE Auto-Pause wirkt bewusst NUR auf Live-Ergebnissen (Demo hat andere Fill-Annahmen
        /// und ist Validierung, kein Kill-Kriterium; in der Demo-Phase pausiert der User manuell).
        /// Nur Master mit gesetztem AutoPauseEnabled; Reaktivierung ausschließlich manuell.
        /// </summary>
        private async Task UpdateCopyScoresAndAutoPauseAsync()
        {
            var since = DateTime.UtcNow.AddDays(-30);

            foreach (var trader in _copyState.Traders.Values.ToList())
            {
                try
                {
                    var closed = _tradeLog
                        .Find(t => t.SourceTraderId == trader.Id && t.ClosedAt >= since)
                        .ToList();
                    var liveMetrics = TraderScore.Compute(closed.Where(t => !t.IsDemo).Select(t => t.RealizedPnl));

                    // Anzeige: Live sobald vorhanden, sonst Demo (Validierungssignal statt leerer Spalten).
                    var display = liveMetrics.TradeCount > 0
                        ? liveMetrics
                        : TraderScore.Compute(closed.Where(t => t.IsDemo).Select(t => t.RealizedPnl));

                    trader.CopyPnl30d = display.CopyPnl;
                    trader.CopyProfitFactor = display.ProfitFactor;
                    trader.CopyAvgPnlPerTrade = display.AvgPnlPerTrade;
                    trader.CopyTradeCount30d = display.TradeCount;

                    // Auto-Pause NUR auf Live-Kennzahlen.
                    bool pause = trader.IsActive && TraderScore.ShouldAutoPause(
                        trader.AutoPauseEnabled, liveMetrics.TradeCount, liveMetrics.CopyPnl,
                        _copyState.AutoPauseMinTrades, _copyState.AutoPauseDrawdownUsd);

                    if (pause)
                    {
                        trader.IsActive = false;
                        trader.Reasoning = $"[Auto-Pause {DateTime.UtcNow:yyyy-MM-dd HH:mm} UTC] Copy-PnL {liveMetrics.CopyPnl:F2} USDC über {liveMetrics.TradeCount} Live-Trades (30T) unter Schwelle (-{_copyState.AutoPauseDrawdownUsd:F0}). Reaktivierung manuell.";
                        _logger.Warning($"🛑 [AUTO-PAUSE] Master '{trader.DisplayName}' deaktiviert. Live-Copy-PnL {liveMetrics.CopyPnl:F2} / {liveMetrics.TradeCount} Trades. Reaktivierung nur manuell.");
                        // Kein try/catch nötig: INotificationSink wirft laut Vertrag nie.
                        await _notify.SendAsync(
                            $"🛑 Auto-Pause: Master '{trader.DisplayName}' deaktiviert.\n" +
                            $"Live-Copy-PnL 30T: {liveMetrics.CopyPnl:F2} USDC über {liveMetrics.TradeCount} Trades.\n" +
                            "Reaktivierung manuell.",
                            NotificationSeverity.Warning);
                    }

                    _copyState.Traders[trader.Id] = trader;   // Hot-Path-State synchron halten
                    _traderRepo.Update(trader);
                }
                catch (Exception ex)
                {
                    _logger.Error($"Copy-Score/Auto-Pause für '{trader.DisplayName}' fehlgeschlagen: {ex.Message}");
                }
            }
        }
    }
}
