using System; using System.Collections.Generic; using System.Windows.Forms; using Microsoft.Extensions.DependencyInjection; using PolyTrader.Core.Analytics; using PolyTrader.Modules.Supervisor.Services; namespace PolyTrader.Modules.Supervisor.Ui { /// /// Hauptfenster des Supervisor-Moduls (S-1): Dossier-Browser — links die jüngsten Signale /// (aus dem Entscheidungsjournal), rechts das komplette Dossier (Markdown). Der Analyse-Chat /// (OpenRouter-Agent) folgt in S-2 als weiterer Tab. Code-only konstruiert (Muster RF-Modul); /// DB-Zugriffe defensiv, damit die UI auch bei leerer/nicht erreichbarer DB bedienbar bleibt. /// public sealed class SupervisorMainForm : Form { private DossierService? _dossiers; private readonly ToolStrip _toolStrip = new(); private readonly ToolStripButton _btnRefresh = new() { Text = "Aktualisieren", DisplayStyle = ToolStripItemDisplayStyle.Text }; private readonly ToolStripLabel _lblSearch = new() { Text = "SignalId:" }; private readonly ToolStripTextBox _tbSignalId = new() { AutoSize = false, Width = 220 }; private readonly ToolStripButton _btnOpen = new() { Text = "Dossier öffnen", DisplayStyle = ToolStripItemDisplayStyle.Text }; private readonly SplitContainer _split = new() { Dock = DockStyle.Fill, SplitterDistance = 420 }; private readonly DataGridView _grid = new() { Dock = DockStyle.Fill, ReadOnly = true, AllowUserToAddRows = false, AllowUserToDeleteRows = false, AutoGenerateColumns = true, SelectionMode = DataGridViewSelectionMode.FullRowSelect, RowHeadersVisible = false, MultiSelect = false }; private readonly TextBox _dossierText = new() { Dock = DockStyle.Fill, Multiline = true, ReadOnly = true, ScrollBars = ScrollBars.Both, Font = new System.Drawing.Font("Consolas", 9.5f), WordWrap = false }; private readonly Label _status = new() { Dock = DockStyle.Bottom, Height = 22, Padding = new Padding(6, 2, 6, 2), Text = "" }; public SupervisorMainForm() { Text = "Supervisor"; Width = 1250; Height = 700; StartPosition = FormStartPosition.CenterScreen; _toolStrip.Items.AddRange(new ToolStripItem[] { _btnRefresh, new ToolStripSeparator(), _lblSearch, _tbSignalId, _btnOpen }); _split.Panel1.Controls.Add(_grid); _split.Panel2.Controls.Add(_dossierText); Controls.Add(_split); Controls.Add(_toolStrip); Controls.Add(_status); _toolStrip.Dock = DockStyle.Top; _btnRefresh.Click += (_, _) => LoadSignals(); _btnOpen.Click += (_, _) => OpenDossier(_tbSignalId.Text.Trim()); _grid.SelectionChanged += (_, _) => OpenSelected(); } public void Initialize(IServiceProvider services) { _dossiers = services.GetRequiredService(); LoadSignals(); } private void LoadSignals() { if (_dossiers == null) return; try { List signals = _dossiers.RecentSignals(200); _grid.DataSource = signals; _status.Text = signals.Count == 0 ? "Noch keine Journal-Einträge (Entscheidungen entstehen, sobald Signale verarbeitet werden)." : $"{signals.Count} Signale."; } catch (Exception ex) { _status.Text = $"Journal nicht lesbar: {ex.Message}"; } } private void OpenSelected() { if (_grid.CurrentRow?.DataBoundItem is SignalSummary s) OpenDossier(s.SignalId); } private void OpenDossier(string signalId) { if (_dossiers == null || string.IsNullOrWhiteSpace(signalId)) return; try { var dossier = _dossiers.BuildForSignal(signalId); _dossierText.Text = DossierBuilder.ToMarkdown(dossier).Replace("\n", Environment.NewLine); _tbSignalId.Text = signalId; } catch (Exception ex) { _dossierText.Text = $"Dossier konnte nicht geladen werden: {ex.Message}"; } } } }