using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Windows.Forms;
using PolyTraderSharp.Services;

namespace PolyTraderSharp.Ui.Views
{
    /// <summary>
    /// Terminal-/Log-Ansicht. Designbar (siehe TerminalView.Designer.cs). Die Laufzeit-
    /// Abhängigkeit (TerminalLogger) wird per <see cref="Initialize"/> injiziert, damit der
    /// parameterlose Konstruktor für den VS-Designer nutzbar bleibt.
    /// </summary>
    public partial class TerminalView : Form
    {
        private TerminalLogger? _logger;
        private readonly ConcurrentQueue<LogMessageEventArgs> _logQueue = new();
        private readonly System.Windows.Forms.Timer _uiLogTimer = new() { Interval = 250 };
        private bool _autoScroll = true;
        private EventHandler<LogMessageEventArgs>? _logHandler;

        public TerminalView()
        {
            InitializeComponent();

            // Steuerelemente + statische Eigenschaften stammen aus dem Designer.
            // Hier nur noch Verhalten verdrahten und einen sinnvollen Default wählen.
            if (cbLogLevel.Items.Count > 0) cbLogLevel.SelectedIndex = 0;
            btnAutoscroll.Click += (_, _) => ToggleAutoscroll();
            _uiLogTimer.Tick += ProcessLogQueue;

            // Kontextmenü: Text aus dem Terminal kopieren (Ctrl+C funktioniert zusätzlich nativ).
            miCopy.Click += (_, _) => { if (rtbTerminal.SelectionLength > 0) rtbTerminal.Copy(); };
            miSelectAll.Click += (_, _) => rtbTerminal.SelectAll();
            miCopyAll.Click += (_, _) => CopyAllToClipboard();
            miClear.Click += (_, _) => rtbTerminal.Clear();

            // Log Viewer (S-0): JSONL-Tagesdateien menschenlesbar, filterbar nach Level/CID/Text.
            if (cbViewerLevel.Items.Count > 0) cbViewerLevel.SelectedIndex = 0;
            btnViewerLoad.Click += (_, _) => LoadViewer();
            tbViewerCid.KeyDown += (_, e) => { if (e.KeyCode == Keys.Enter) { LoadViewer(); e.SuppressKeyPress = true; } };
            tbViewerText.KeyDown += (_, e) => { if (e.KeyCode == Keys.Enter) { LoadViewer(); e.SuppressKeyPress = true; } };
            // Doppelklick auf eine CID: komplette Signal-Kette anzeigen.
            dgvLogs.CellDoubleClick += (_, e) =>
            {
                if (e.RowIndex < 0) return;
                if (dgvLogs.Rows[e.RowIndex].DataBoundItem is LogViewerRow row && !string.IsNullOrEmpty(row.Cid))
                {
                    tbViewerCid.Text = row.Cid;
                    tbViewerText.Text = "";
                    LoadViewer();
                }
            };
        }

        // ===== Log Viewer =====

        /// <summary>Anzeige-Zeile des Log Viewers (Bindung über DataPropertyName).</summary>
        private sealed class LogViewerRow
        {
            public string Time { get; init; } = "";
            public string Level { get; init; } = "";
            public string Cid { get; init; } = "";
            public string Message { get; init; } = "";
        }

        private void LoadViewer()
        {
            try
            {
                string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs",
                    $"{dtViewerDate.Value:yyyy-MM-dd}.jsonl");
                if (!System.IO.File.Exists(path))
                {
                    dgvLogs.DataSource = new System.ComponentModel.BindingList<LogViewerRow>();
                    lblViewerStatus.Text = "Keine JSONL-Datei für dieses Datum.";
                    return;
                }

                string levelFilter = cbViewerLevel.SelectedItem?.ToString() ?? "Alle";
                string cidFilter = tbViewerCid.Text.Trim();
                string textFilter = tbViewerText.Text.Trim();

                var rows = new List<LogViewerRow>();
                foreach (string line in System.IO.File.ReadLines(path))
                {
                    var p = LogJson.ParseLine(line);
                    if (p == null) continue;
                    if (levelFilter != "Alle" && p.Level != levelFilter) continue;
                    if (cidFilter.Length > 0 && !p.Cid.Contains(cidFilter, StringComparison.OrdinalIgnoreCase)) continue;
                    if (textFilter.Length > 0 && !p.Message.Contains(textFilter, StringComparison.OrdinalIgnoreCase)) continue;
                    rows.Add(new LogViewerRow { Time = p.Time, Level = p.Level, Cid = p.Cid, Message = p.Message });
                    if (rows.Count >= 20000) break;   // UI-Schutz bei sehr großen Tagen
                }

                dgvLogs.DataSource = new System.ComponentModel.BindingList<LogViewerRow>(rows);
                lblViewerStatus.Text = $"{rows.Count} Einträge.";
            }
            catch (Exception ex)
            {
                lblViewerStatus.Text = $"Fehler: {ex.Message}";
            }
        }

        private void CopyAllToClipboard()
        {
            try
            {
                if (!string.IsNullOrEmpty(rtbTerminal.Text))
                    Clipboard.SetText(rtbTerminal.Text);
            }
            catch { /* Zwischenablage kann kurzzeitig belegt sein – bewusst ignorieren */ }
        }

        /// <summary>Verbindet die View mit dem Logger (Laufzeit-DI).</summary>
        public void Initialize(TerminalLogger logger)
        {
            _logger = logger;

            // Jüngste Historie vorladen, damit das Fenster beim Öffnen nicht leer ist.
            foreach (var e in _logger.GetHistory(TimeSpan.FromMinutes(10)))
                _logQueue.Enqueue(e);

            _logHandler = (_, e) => _logQueue.Enqueue(e);
            _logger.OnLogMessage += _logHandler;

            _uiLogTimer.Start();
            Disposed += OnDisposed;
        }

        private void OnDisposed(object? sender, EventArgs e)
        {
            _uiLogTimer.Stop();
            if (_logger != null && _logHandler != null)
                _logger.OnLogMessage -= _logHandler;
        }

        private void ToggleAutoscroll()
        {
            _autoScroll = !_autoScroll;
            btnAutoscroll.BackColor = _autoScroll ? System.Drawing.Color.LightGreen : System.Drawing.Color.IndianRed;
            btnAutoscroll.Text = _autoScroll ? "Stop Autoscroll" : "Start Autoscroll";
        }

        private void ProcessLogQueue(object? sender, EventArgs e)
        {
            if (_logQueue.IsEmpty || !IsHandleCreated) return;

            string filter = cbLogLevel.SelectedItem?.ToString() ?? "Alle";
            TimeZoneInfo berlinTz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
            bool appended = false;
            int count = 0;
            const int maxProcess = 500;

            rtbTerminal.SuspendLayout();

            while (count < maxProcess && _logQueue.TryDequeue(out var logEvent))
            {
                count++;
                if (filter != "Alle" && logEvent.Level.ToString() != filter) continue;

                DateTime logTime = logEvent.Timestamp.Kind == DateTimeKind.Utc
                    ? TimeZoneInfo.ConvertTimeFromUtc(logEvent.Timestamp, berlinTz)
                    : TimeZoneInfo.ConvertTime(logEvent.Timestamp, berlinTz);
                string timeStr = $"[{logTime:HH:mm:ss}]";

                System.Drawing.Color c = System.Drawing.Color.White;
                if (logEvent.Level == LogLevel.Error) c = System.Drawing.Color.Red;
                else if (logEvent.Level == LogLevel.Warning) c = System.Drawing.Color.Yellow;
                else if (logEvent.Level == LogLevel.Trade) c = System.Drawing.Color.LightGreen;
                else if (logEvent.Level == LogLevel.TradeReasoning) c = System.Drawing.Color.Orange;

                rtbTerminal.SelectionStart = rtbTerminal.TextLength;
                rtbTerminal.SelectionLength = 0;
                rtbTerminal.SelectionColor = c;
                rtbTerminal.AppendText($"{timeStr} [{logEvent.Level}] {logEvent.Message}\n");
                appended = true;
            }

            if (appended)
            {
                if (rtbTerminal.TextLength > 80000)
                {
                    rtbTerminal.Clear();
                    rtbTerminal.SelectionColor = System.Drawing.Color.LightPink;
                    rtbTerminal.AppendText($"[{DateTime.Now:HH:mm:ss}] [System] Terminal Auto-Clear (RAM Limit erreicht). Vollständige Logs im Ordner /Logs.\n");
                }

                if (_autoScroll) rtbTerminal.ScrollToCaret();
            }

            rtbTerminal.ResumeLayout();
        }
    }
}
