using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PolyTraderSharp.Models;
using PolyTraderSharp.Services;

namespace PolyTrader.Core.Analytics
{
    /// <summary>
    /// Das „Trade-Dossier" (S-1, Supervisor-Konzept): alles, was zu einem Signal gehört —
    /// Entscheidungen, Order-Events, abgeschlossene Trades, Log-Zeilen — als eine Einheit.
    /// Grundlage für den Dossier-Browser (Mensch) und die KI-Analyse (S-2).
    /// </summary>
    public sealed class TradeDossier
    {
        public string SignalId { get; init; } = string.Empty;
        public string ModuleName { get; init; } = string.Empty;
        public int AccountId { get; init; }
        public string TokenId { get; init; } = string.Empty;
        public string MarketQuestion { get; init; } = string.Empty;
        public string Side { get; init; } = string.Empty;

        public List<DecisionRecord> Decisions { get; init; } = new();
        public List<OrderEventRecord> OrderEvents { get; init; } = new();
        public List<TradeRecord> ClosedTrades { get; init; } = new();
        public List<LogJson.ParsedLogLine> LogLines { get; init; } = new();
    }

    /// <summary>
    /// Reiner Zusammenbau + Markdown-Rendering eines Dossiers. Seiteneffektfrei und unit-getestet;
    /// die Datenbeschaffung (Repos/JSONL) macht der DossierService des Supervisor-Moduls.
    /// </summary>
    public static class DossierBuilder
    {
        /// <summary>Baut das Dossier aus bereits auf die SignalId gescopten Daten (sortiert chronologisch).</summary>
        public static TradeDossier Build(
            string signalId,
            IEnumerable<DecisionRecord> decisions,
            IEnumerable<OrderEventRecord> orderEvents,
            IEnumerable<TradeRecord> closedTrades,
            IEnumerable<LogJson.ParsedLogLine>? logLines = null)
        {
            var dec = decisions.OrderBy(d => d.Timestamp).ToList();
            var ev = orderEvents.OrderBy(e => e.Timestamp).ToList();
            var trades = closedTrades.OrderBy(t => t.ClosedAt).ToList();
            var first = dec.FirstOrDefault();

            return new TradeDossier
            {
                SignalId = signalId,
                ModuleName = first?.ModuleName ?? trades.FirstOrDefault()?.ModuleName ?? string.Empty,
                AccountId = first?.AccountId ?? trades.FirstOrDefault()?.AccountId ?? 0,
                TokenId = first?.TokenId ?? trades.FirstOrDefault()?.TokenId ?? string.Empty,
                MarketQuestion = first?.MarketQuestion ?? trades.FirstOrDefault()?.MarketQuestion ?? string.Empty,
                Side = first?.Side ?? string.Empty,
                Decisions = dec,
                OrderEvents = ev,
                ClosedTrades = trades,
                LogLines = (logLines ?? Enumerable.Empty<LogJson.ParsedLogLine>()).ToList()
            };
        }

        /// <summary>Menschenlesbare Markdown-Fassung (Dossier-Browser; auch als KI-Input geeignet).</summary>
        public static string ToMarkdown(TradeDossier d)
        {
            var sb = new StringBuilder();
            sb.AppendLine($"# Dossier {ShortId(d.SignalId)}");
            sb.AppendLine();
            sb.AppendLine($"- **Markt:** {d.MarketQuestion}");
            sb.AppendLine($"- **Modul:** {d.ModuleName}   **Konto:** {d.AccountId}   **Side:** {d.Side}");
            sb.AppendLine($"- **TokenId:** {d.TokenId}");
            sb.AppendLine($"- **SignalId:** {d.SignalId}");

            decimal pnl = d.ClosedTrades.Sum(t => t.RealizedPnl);
            sb.AppendLine($"- **Ergebnis:** {d.ClosedTrades.Count} Trade(s), realisierter PnL {pnl:F2} USDC");
            sb.AppendLine();

            if (d.Decisions.Count > 0)
            {
                sb.AppendLine("## Entscheidungen");
                sb.AppendLine();
                sb.AppendLine("| Zeit (UTC) | Entscheidung | Grund | Details |");
                sb.AppendLine("|---|---|---|---|");
                foreach (var x in d.Decisions)
                    sb.AppendLine($"| {x.Timestamp:dd.MM. HH:mm:ss} | {x.Decision} | {x.Reason} | {Escape(x.Message)} {(string.IsNullOrEmpty(x.ContextJson) ? "" : "`" + x.ContextJson + "`")} |");
                sb.AppendLine();
            }

            if (d.OrderEvents.Count > 0)
            {
                sb.AppendLine("## Order-Events");
                sb.AppendLine();
                sb.AppendLine("| Zeit (UTC) | Event | Side | Preis | USDC | Antwort |");
                sb.AppendLine("|---|---|---|---|---|---|");
                foreach (var x in d.OrderEvents)
                    sb.AppendLine($"| {x.Timestamp:dd.MM. HH:mm:ss} | {x.EventType} | {x.Side} | {x.Price:F3} | {x.AmountUsd:F2} | {Escape(x.Response)} |");
                sb.AppendLine();
            }

            if (d.ClosedTrades.Count > 0)
            {
                sb.AppendLine("## Abgeschlossene Trades");
                sb.AppendLine();
                sb.AppendLine("| Geschlossen (UTC) | Entry | Exit | Size | PnL | Grund |");
                sb.AppendLine("|---|---|---|---|---|---|");
                foreach (var t in d.ClosedTrades)
                    sb.AppendLine($"| {t.ClosedAt:dd.MM. HH:mm:ss} | {t.EntryPrice:F3} | {t.ExitPrice:F3} | {t.Size:F2} | {t.RealizedPnl:F2} | {Escape(t.ExitReason)} |");
                sb.AppendLine();
            }

            if (d.LogLines.Count > 0)
            {
                sb.AppendLine("## Log-Auszug");
                sb.AppendLine();
                foreach (var l in d.LogLines)
                    sb.AppendLine($"- `{l.Time}` **{l.Level}** {Escape(l.Message)}");
                sb.AppendLine();
            }

            if (d.Decisions.Count == 0 && d.OrderEvents.Count == 0 && d.ClosedTrades.Count == 0)
                sb.AppendLine("*Keine Daten zu dieser SignalId gefunden.*");

            return sb.ToString();
        }

        private static string ShortId(string id) => string.IsNullOrEmpty(id) ? "(ohne SignalId)" : id[..Math.Min(8, id.Length)];

        private static string Escape(string s) =>
            (s ?? string.Empty).Replace("|", "\\|").Replace("\r\n", " ").Replace("\n", " ");
    }
}
