VBAF.Visualization.MarketDashboard.ps1

#Requires -Version 5.1
# VBAF.Visualization.MarketDashboard.ps1
# Dashboard 2 - WALL STREET EDITION
<#
.SYNOPSIS
    Wall Street-style market dashboard for multi-agent simulation
.DESCRIPTION
    Bloomberg Terminal aesthetic: Central profit graph surrounded by info panels.
    Shows market share, economic indicators, decisions, events, and learning stats.
.NOTES
    Part of VBAF (Visual Business Automation Framework)
    WALL STREET EDITION - Professional trading floor aesthetic
#>


class MarketDashboard {
    # Form and panels
    [System.Windows.Forms.Form]$Form
    
    # Info panels (surrounding the main graph)
    [System.Windows.Forms.Panel]$PanelMarketShare      # Top-left
    [System.Windows.Forms.Panel]$PanelQuarterInfo      # Top-center
    [System.Windows.Forms.Panel]$PanelEconomic         # Top-right
    [System.Windows.Forms.Panel]$PanelDecisions        # Middle-right
    [System.Windows.Forms.Panel]$PanelLearning         # Bottom-right
    [System.Windows.Forms.Panel]$PanelEvents           # Bottom-left
    
    # MAIN GRAPH (center stage)
    [System.Windows.Forms.Panel]$PanelMainGraph
    
    # Control panel
    [System.Windows.Forms.Panel]$ControlPanel
    
    # Controls
    [System.Windows.Forms.Button]$BtnPlay
    [System.Windows.Forms.TrackBar]$SpeedSlider
    [System.Windows.Forms.Label]$SpeedLabel
    
    # Data source
    $Market  # MarketEnvironment object
    
    # History tracking
    [System.Collections.ArrayList]$ProfitHistory
    [System.Collections.ArrayList]$MarketShareHistory
    [System.Collections.ArrayList]$EventLog
    [System.Collections.ArrayList]$DecisionHistory
    
    # Animation
    [System.Windows.Forms.Timer]$Timer
    [bool]$IsPlaying
    [int]$Speed  # 1-10
    
    # Colors (Wall Street neon palette)
    [hashtable]$CompanyColors
    
    # Constructor
    MarketDashboard($marketEnvironment) {
        $this.Market = $marketEnvironment
        $this.ProfitHistory = New-Object System.Collections.ArrayList
        $this.MarketShareHistory = New-Object System.Collections.ArrayList
        $this.EventLog = New-Object System.Collections.ArrayList
        $this.DecisionHistory = New-Object System.Collections.ArrayList
        $this.IsPlaying = $false
        $this.Speed = 1
        
        # Wall Street color palette
        $this.CompanyColors = @{
            0 = [System.Drawing.Color]::FromArgb(0, 255, 255)    # Cyan
            1 = [System.Drawing.Color]::FromArgb(255, 128, 0)    # Orange
            2 = [System.Drawing.Color]::FromArgb(0, 255, 128)    # Lime
            3 = [System.Drawing.Color]::FromArgb(255, 0, 255)    # Magenta
        }
        
        $this.InitializeForm()
        $this.InitializePanels()
        $this.InitializeControls()
        $this.InitializeTimer()
        
        $this.LogEvent("🔔 Dashboard initialized - Wall Street mode activated!")
    }
    
    [void] InitializeForm() {
        $this.Form = New-Object System.Windows.Forms.Form
        $this.Form.Width = 1600
        $this.Form.Height = 1000
        $this.Form.Text = "VBAF Market Dashboard - Wall Street Edition"
        $this.Form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
        $this.Form.BackColor = [System.Drawing.Color]::FromArgb(10, 10, 10)  # Pure black
        $this.Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog
        $this.Form.MaximizeBox = $false
    }
    
    [void] InitializePanels() {
        $dashboard = $this
        
        # === TOP ROW (3 info panels) ===
        
        # Market Share (top-left)
        $this.PanelMarketShare = New-Object System.Windows.Forms.Panel
        $this.PanelMarketShare.Location = New-Object System.Drawing.Point(10, 10)
        $this.PanelMarketShare.Size = New-Object System.Drawing.Size(380, 180)
        $this.PanelMarketShare.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelMarketShare.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelMarketShare)
        $this.PanelMarketShare.Add_Paint({ param($s, $e) $dashboard.DrawMarketSharePanel($s, $e) })
        $this.Form.Controls.Add($this.PanelMarketShare)
        
        # Quarter Info (top-center)
        $this.PanelQuarterInfo = New-Object System.Windows.Forms.Panel
        $this.PanelQuarterInfo.Location = New-Object System.Drawing.Point(400, 10)
        $this.PanelQuarterInfo.Size = New-Object System.Drawing.Size(380, 180)
        $this.PanelQuarterInfo.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelQuarterInfo.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelQuarterInfo)
        $this.PanelQuarterInfo.Add_Paint({ param($s, $e) $dashboard.DrawQuarterInfoPanel($s, $e) })
        $this.Form.Controls.Add($this.PanelQuarterInfo)
        
        # Economic Indicators (top-right)
        $this.PanelEconomic = New-Object System.Windows.Forms.Panel
        $this.PanelEconomic.Location = New-Object System.Drawing.Point(790, 10)
        $this.PanelEconomic.Size = New-Object System.Drawing.Size(380, 180)
        $this.PanelEconomic.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelEconomic.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelEconomic)
        $this.PanelEconomic.Add_Paint({ param($s, $e) $dashboard.DrawEconomicPanel($s, $e) })
        $this.Form.Controls.Add($this.PanelEconomic)
        
        # === MAIN GRAPH (center stage) ===
        
        $this.PanelMainGraph = New-Object System.Windows.Forms.Panel
        $this.PanelMainGraph.Location = New-Object System.Drawing.Point(10, 200)
        $this.PanelMainGraph.Size = New-Object System.Drawing.Size(1160, 520)
        $this.PanelMainGraph.BackColor = [System.Drawing.Color]::FromArgb(15, 15, 20)
        $this.PanelMainGraph.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelMainGraph)
        $this.PanelMainGraph.Add_Paint({ param($s, $e) $dashboard.DrawMainGraph($s, $e) })
        $this.Form.Controls.Add($this.PanelMainGraph)
        
        # === RIGHT COLUMN (2 info panels) ===
        
        # Recent Decisions (middle-right)
        $this.PanelDecisions = New-Object System.Windows.Forms.Panel
        $this.PanelDecisions.Location = New-Object System.Drawing.Point(1180, 200)
        $this.PanelDecisions.Size = New-Object System.Drawing.Size(390, 260)
        $this.PanelDecisions.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelDecisions.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelDecisions)
        $this.PanelDecisions.Add_Paint({ param($s, $e) $dashboard.DrawDecisionsPanel($s, $e) })
        $this.Form.Controls.Add($this.PanelDecisions)
        
        # Learning Stats (bottom-right)
        $this.PanelLearning = New-Object System.Windows.Forms.Panel
        $this.PanelLearning.Location = New-Object System.Drawing.Point(1180, 470)
        $this.PanelLearning.Size = New-Object System.Drawing.Size(390, 250)
        $this.PanelLearning.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelLearning.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelLearning)
        $this.PanelLearning.Add_Paint({ param($s, $e) $dashboard.DrawLearningPanel($s, $e) })
        $this.Form.Controls.Add($this.PanelLearning)
        
        # === BOTTOM (Event Log) ===
        
        $this.PanelEvents = New-Object System.Windows.Forms.Panel
        $this.PanelEvents.Location = New-Object System.Drawing.Point(10, 730)
        $this.PanelEvents.Size = New-Object System.Drawing.Size(1560, 160)
        $this.PanelEvents.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 25)
        $this.PanelEvents.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.EnableDoubleBuffering($this.PanelEvents)
        $this.PanelEvents.Add_Paint({ param($s, $e) $dashboard.DrawEventsPanel($s, $e) })
        $this.Form.Controls.Add($this.PanelEvents)
        
        # === CONTROL PANEL ===
        
        $this.ControlPanel = New-Object System.Windows.Forms.Panel
        $this.ControlPanel.Location = New-Object System.Drawing.Point(10, 900)
        $this.ControlPanel.Size = New-Object System.Drawing.Size(1560, 50)
        $this.ControlPanel.BackColor = [System.Drawing.Color]::FromArgb(30, 30, 35)
        $this.ControlPanel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $this.Form.Controls.Add($this.ControlPanel)
    }
    
    [void] EnableDoubleBuffering($panel) {
        $prop = $panel.GetType().GetProperty("DoubleBuffered", 
            [System.Reflection.BindingFlags]"Instance,NonPublic")
        $prop.SetValue($panel, $true, $null)
    }
    
    [void] InitializeControls() {
        $dashboard = $this
        
        # Play/Pause Button
        $this.BtnPlay = New-Object System.Windows.Forms.Button
        $this.BtnPlay.Location = New-Object System.Drawing.Point(20, 10)
        $this.BtnPlay.Size = New-Object System.Drawing.Size(100, 30)
        $this.BtnPlay.Text = "▶ PLAY"
        $this.BtnPlay.BackColor = [System.Drawing.Color]::FromArgb(0, 180, 0)
        $this.BtnPlay.ForeColor = [System.Drawing.Color]::White
        $this.BtnPlay.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
        $this.BtnPlay.Font = New-Object System.Drawing.Font("Consolas", 10, [System.Drawing.FontStyle]::Bold)
        $this.BtnPlay.Add_Click({ $dashboard.TogglePlay() })
        $this.ControlPanel.Controls.Add($this.BtnPlay)
        
        # Step Button
        $btnStep = New-Object System.Windows.Forms.Button
        $btnStep.Location = New-Object System.Drawing.Point(130, 10)
        $btnStep.Size = New-Object System.Drawing.Size(100, 30)
        $btnStep.Text = "⏭ STEP"
        $btnStep.BackColor = [System.Drawing.Color]::FromArgb(80, 80, 100)
        $btnStep.ForeColor = [System.Drawing.Color]::White
        $btnStep.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
        $btnStep.Font = New-Object System.Drawing.Font("Consolas", 8, [System.Drawing.FontStyle]::Bold)
        $btnStep.Add_Click({ $dashboard.StepQuarter() })
        $this.ControlPanel.Controls.Add($btnStep)
        
        # Reset Button
        $btnReset = New-Object System.Windows.Forms.Button
        $btnReset.Location = New-Object System.Drawing.Point(240, 10)
        $btnReset.Size = New-Object System.Drawing.Size(100, 30)
        $btnReset.Text = "🔄 RESET"
        $btnReset.BackColor = [System.Drawing.Color]::FromArgb(180, 0, 0)
        $btnReset.ForeColor = [System.Drawing.Color]::White
        $btnReset.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
        $btnReset.Font = New-Object System.Drawing.Font("Consolas", 8, [System.Drawing.FontStyle]::Bold)
        $btnReset.Add_Click({ $dashboard.ResetSimulation() })
        $this.ControlPanel.Controls.Add($btnReset)
        
        # Speed Label
        $this.SpeedLabel = New-Object System.Windows.Forms.Label
        $this.SpeedLabel.Location = New-Object System.Drawing.Point(370, 15)
        $this.SpeedLabel.Size = New-Object System.Drawing.Size(100, 20)
        $this.SpeedLabel.Text = "SPEED: 1x"
        $this.SpeedLabel.ForeColor = [System.Drawing.Color]::Cyan
        $this.SpeedLabel.Font = New-Object System.Drawing.Font("Consolas", 8, [System.Drawing.FontStyle]::Bold)
        $this.ControlPanel.Controls.Add($this.SpeedLabel)
        
        # Speed Slider
        $this.SpeedSlider = New-Object System.Windows.Forms.TrackBar
        $this.SpeedSlider.Location = New-Object System.Drawing.Point(480, 5)
        $this.SpeedSlider.Size = New-Object System.Drawing.Size(250, 40)
        $this.SpeedSlider.Minimum = 1
        $this.SpeedSlider.Maximum = 10
        $this.SpeedSlider.Value = 1
        $this.SpeedSlider.TickFrequency = 1
        $this.SpeedSlider.BackColor = [System.Drawing.Color]::FromArgb(30, 30, 35)
        $this.SpeedSlider.Add_ValueChanged({ 
            $dashboard.Speed = $dashboard.SpeedSlider.Value
            $dashboard.SpeedLabel.Text = "SPEED: $($dashboard.Speed)x"
            if ($dashboard.IsPlaying) {
                $dashboard.Timer.Interval = [Math]::Max(100, (1000 / $dashboard.Speed))
            }
        })
        $this.ControlPanel.Controls.Add($this.SpeedSlider)
        
        # Export Button
        $btnExport = New-Object System.Windows.Forms.Button
        $btnExport.Location = New-Object System.Drawing.Point(1430, 10)
        $btnExport.Size = New-Object System.Drawing.Size(100, 30)
        $btnExport.Text = "💾 EXPORT"
        $btnExport.BackColor = [System.Drawing.Color]::FromArgb(100, 100, 120)
        $btnExport.ForeColor = [System.Drawing.Color]::White
        $btnExport.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
        $btnExport.Font = New-Object System.Drawing.Font("Consolas", 8, [System.Drawing.FontStyle]::Bold)
        $btnExport.Add_Click({ $dashboard.ExportData() })
        $this.ControlPanel.Controls.Add($btnExport)
    }
    
    [void] InitializeTimer() {
        $dashboard = $this
        
        $this.Timer = New-Object System.Windows.Forms.Timer
        $this.Timer.Interval = 1000
        $this.Timer.Add_Tick({ 
            if ($dashboard.IsPlaying) {
                $dashboard.StepQuarter()
            }
        })
    }
    
    # ==================== CONTROL METHODS ====================
    
    [void] TogglePlay() {
        $this.IsPlaying = -not $this.IsPlaying
        
        if ($this.IsPlaying) {
            $this.BtnPlay.Text = "⏸ PAUSE"
            $this.BtnPlay.BackColor = [System.Drawing.Color]::FromArgb(255, 140, 0)
            $this.Timer.Interval = [Math]::Max(100, (1000 / $this.Speed))
            $this.Timer.Start()
            $this.LogEvent("▶ AUTO-PLAY started at $($this.Speed)x speed")
        } else {
            $this.BtnPlay.Text = "▶ PLAY"
            $this.BtnPlay.BackColor = [System.Drawing.Color]::FromArgb(0, 180, 0)
            $this.Timer.Stop()
            $this.LogEvent("⏸ AUTO-PLAY paused")
        }
    }
    
    [void] StepQuarter() {
        # Simulate one quarter
        $this.Market.SimulateQuarter()
        
        # Capture data
        $this.CaptureSnapshot()
        
        # Check for major events
        $this.CheckForMajorEvents()
        
        # Refresh all panels
        $this.RefreshAll()
    }
    
    [void] ResetSimulation() {
        # Stop playback
        $this.IsPlaying = $false
        $this.Timer.Stop()
        $this.BtnPlay.Text = "▶ PLAY"
        $this.BtnPlay.BackColor = [System.Drawing.Color]::FromArgb(0, 180, 0)
        
        # Reset market
        if ($this.Market.PSObject.Methods['Reset']) {
            $this.Market.Reset()
        } else {
            $this.Market.CurrentQuarter = 1
        }
        
        # Clear history
        $this.ProfitHistory.Clear()
        $this.MarketShareHistory.Clear()
        $this.EventLog.Clear()
        $this.DecisionHistory.Clear()
        
        # Log reset
        $this.LogEvent("🔄 SYSTEM RESET - Starting fresh simulation")
        
        # Refresh all panels
        $this.RefreshAll()
    }
    
    [void] RefreshAll() {
        $this.PanelMarketShare.Invalidate()
        $this.PanelQuarterInfo.Invalidate()
        $this.PanelEconomic.Invalidate()
        $this.PanelMainGraph.Invalidate()
        $this.PanelDecisions.Invalidate()
        $this.PanelLearning.Invalidate()
        $this.PanelEvents.Invalidate()
    }
    
    # ==================== DATA CAPTURE ====================
    
    [void] CaptureSnapshot() {
        $snapshot = @{
            Quarter = $this.Market.CurrentQuarter
            Profits = @{}
            MarketShares = @{}
            Decisions = @{}
        }
        
        foreach ($company in $this.Market.Companies) {
            $snapshot.Profits[$company.Name] = [double]$company.State.Profit
            $snapshot.MarketShares[$company.Name] = [double]$company.State.MarketShare
            
            if ($company.PSObject.Properties['LastAction'] -and $null -ne $company.LastAction) {
                $snapshot.Decisions[$company.Name] = $company.LastAction.Name
            } else {
                $snapshot.Decisions[$company.Name] = "Hold"
            }
        }
        
        [void]$this.ProfitHistory.Add($snapshot)
        [void]$this.DecisionHistory.Add($snapshot)
    }
    
    [void] CheckForMajorEvents() {
        if ($this.ProfitHistory.Count -lt 2) { return }
        
        $current = $this.ProfitHistory[-1]
        $previous = $this.ProfitHistory[-2]
        
        foreach ($company in $this.Market.Companies) {
            $name = $company.Name
            $currProfit = $current.Profits[$name]
            $prevProfit = $previous.Profits[$name]
            
            # Big profit changes
            if ($prevProfit -gt 0) {
                $change = (($currProfit - $prevProfit) / $prevProfit) * 100
                if ($change -gt 50) {
                    $this.LogEvent("📈 $name SURGE: Profit +$([Math]::Round($change, 1))%!")
                }
                if ($change -lt -30) {
                    $this.LogEvent("📉 $name DROP: Profit $([Math]::Round($change, 1))%")
                }
            }
            
            # Market share milestones
            $share = $current.MarketShares[$name] * 100
            if ($share -gt 30 -and ($previous.MarketShares[$name] * 100) -le 30) {
                $this.LogEvent("🏆 $name dominates: 30% market share!")
            }
        }
    }
    
    [void] LogEvent([string]$message) {
        $timestamp = "Q$($this.Market.CurrentQuarter)"
        $entry = "[$timestamp] $message"
        [void]$this.EventLog.Add($entry)
        
        # Keep only last 100 events
        if ($this.EventLog.Count -gt 100) {
            $this.EventLog.RemoveAt(0)
        }
    }
    
    # ==================== DRAWING METHODS ====================
    
    [void] DrawMarketSharePanel($sender, $e) {
        $g = $e.Graphics
        $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 12, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("MARKET SHARE", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        # Draw pie chart with INSIDE labels
        if ($this.Market.Companies.Count -eq 0) { return }
        
        $diameter = 140
        $x = ($sender.Width - $diameter) / 2
        $y = 35
        
        $startAngle = 0.0
        $totalShare = 0.0
        
        foreach ($company in $this.Market.Companies) {
            $totalShare += $company.State.MarketShare
        }
        if ($totalShare -eq 0) { $totalShare = 1.0 }
        
        # Draw pie slices
        for ($i = 0; $i -lt $this.Market.Companies.Count; $i++) {
            $company = $this.Market.Companies[$i]
            $share = [double]$company.State.MarketShare
            $sweepAngle = ($share / $totalShare) * 360.0
            
            $color = $this.CompanyColors[$i]
            $brush = New-Object System.Drawing.SolidBrush($color)
            $rect = New-Object System.Drawing.Rectangle([int]$x, [int]$y, [int]$diameter, [int]$diameter)
            $g.FillPie($brush, $rect, [float]$startAngle, [float]$sweepAngle)
            $brush.Dispose()
            
            # Draw percentage INSIDE the slice
            $pct = [Math]::Round(($share * 100), 1)
            $labelAngle = $startAngle + ($sweepAngle / 2.0)
            $radians = $labelAngle * [Math]::PI / 180.0
            $halfDiam = $diameter / 2.0
            
            # Position label 60% from center (inside the slice)
            $labelDistance = $halfDiam * 0.6
            $labelX = $x + $halfDiam + ([Math]::Cos($radians) * $labelDistance) - 15
            $labelY = $y + $halfDiam + ([Math]::Sin($radians) * $labelDistance) - 7
            
            # Draw percentage with white text and black outline for visibility
            $labelFont = New-Object System.Drawing.Font("Consolas", 9, [System.Drawing.FontStyle]::Bold)
            $labelText = "$pct%"
            
            # Black outline (draw multiple times slightly offset)
            $blackBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Black)
            for ($dx = -1; $dx -le 1; $dx++) {
                for ($dy = -1; $dy -le 1; $dy++) {
                    if ($dx -ne 0 -or $dy -ne 0) {
                        $g.DrawString($labelText, $labelFont, $blackBrush, $labelX + $dx, $labelY + $dy)
                    }
                }
            }
            $blackBrush.Dispose()
            
            # White text on top
            $whiteBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
            $g.DrawString($labelText, $labelFont, $whiteBrush, $labelX, $labelY)
            $whiteBrush.Dispose()
            $labelFont.Dispose()
            
            $startAngle += $sweepAngle
        }
        
        # Company names below pie chart
        $font = New-Object System.Drawing.Font("Consolas", 8)
        $yLegend = $y + $diameter + 5
        
        for ($i = 0; $i -lt $this.Market.Companies.Count; $i++) {
            $company = $this.Market.Companies[$i]
            $color = $this.CompanyColors[$i]
            
            # Color box
            $brush = New-Object System.Drawing.SolidBrush($color)
            $g.FillRectangle($brush, 10, $yLegend, 12, 12)
            $brush.Dispose()
            
            # Company name
            $textBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
            $text = $company.Name
            $g.DrawString($text, $font, $textBrush, 28, $yLegend)
            $textBrush.Dispose()
            
            $yLegend += 14
        }
        
        $font.Dispose()
    }
    
    [void] DrawQuarterInfoPanel($sender, $e) {
        $g = $e.Graphics
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 12, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("SIMULATION STATUS", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        # Info
        $font = New-Object System.Drawing.Font("Consolas", 10)
        $brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
        
        $qtr = if ($this.Market.PSObject.Properties['CurrentQuarter']) { $this.Market.CurrentQuarter } else { 1 }
        $g.DrawString("Quarter: $qtr", $font, $brush, 20, 50)
        
        $statusText = if ($this.IsPlaying) { "RUNNING" } else { "PAUSED" }
        $statusColor = if ($this.IsPlaying) { 
            [System.Drawing.Color]::LimeGreen 
        } else { 
            [System.Drawing.Color]::Orange 
        }
        $statusBrush = New-Object System.Drawing.SolidBrush($statusColor)
        $g.DrawString("Status: $statusText", $font, $statusBrush, 20, 80)
        $statusBrush.Dispose()
        
        $g.DrawString("Speed: $($this.Speed)x", $font, $brush, 20, 110)
        
        $dataPoints = $this.ProfitHistory.Count
        $g.DrawString("Data Points: $dataPoints", $font, $brush, 20, 140)
        
        $font.Dispose()
        $brush.Dispose()
    }
    
    [void] DrawEconomicPanel($sender, $e) {
        $g = $e.Graphics
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 12, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("ECONOMIC INDICATORS", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        # Indicators
        $font = New-Object System.Drawing.Font("Consolas", 10)
        $brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
        
        $gdp = if ($this.Market.PSObject.Properties['EconomyGrowth']) { 
            [double]$this.Market.EconomyGrowth 
        } else { 0.02 }
        $gdpPct = [Math]::Round(($gdp * 100), 2)
        $g.DrawString("GDP Growth: $gdpPct%", $font, $brush, 20, 50)
        
        $interest = if ($this.Market.PSObject.Properties['InterestRate']) {
            [double]$this.Market.InterestRate
        } else { 0.05 }
        $intPct = [Math]::Round(($interest * 100), 2)
        $g.DrawString("Interest Rate: $intPct%", $font, $brush, 20, 80)
        
        $condition = if ($this.Market.PSObject.Properties['MarketCondition']) {
            $this.Market.MarketCondition
        } else { "Neutral" }
        $condColor = switch ($condition) {
            "Bull" { [System.Drawing.Color]::LimeGreen }
            "Bear" { [System.Drawing.Color]::Red }
            default { [System.Drawing.Color]::Yellow }
        }
        $condBrush = New-Object System.Drawing.SolidBrush($condColor)
        $g.DrawString("Market: $condition", $font, $condBrush, 20, 110)
        $condBrush.Dispose()
        
        $font.Dispose()
        $brush.Dispose()
    }
    
    [void] DrawMainGraph($sender, $e) {
        $g = $e.Graphics
        $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(15, 15, 20))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 16, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(0, 255, 255))
        $title = "PROFIT PERFORMANCE - REAL-TIME"
        $titleSize = $g.MeasureString($title, $titleFont)
        $titleX = ($sender.Width - $titleSize.Width) / 2
        $g.DrawString($title, $titleFont, $titleBrush, $titleX, 15)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        if ($this.ProfitHistory.Count -lt 2) {
            $msgFont = New-Object System.Drawing.Font("Consolas", 14)
            $msgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Gray)
            $msg = "Press STEP or PLAY to start simulation..."
            $msgSize = $g.MeasureString($msg, $msgFont)
            $msgX = ($sender.Width - $msgSize.Width) / 2
            $msgY = ($sender.Height - $msgSize.Height) / 2
            $g.DrawString($msg, $msgFont, $msgBrush, $msgX, $msgY)
            $msgFont.Dispose()
            $msgBrush.Dispose()
            return
        }
        
        # Graph area
        $marginLeft = 60
        $marginRight = 40
        $marginTop = 60
        $marginBottom = 90  # Increased to make room for legend below
        
        $graphWidth = $sender.Width - $marginLeft - $marginRight
        $graphHeight = $sender.Height - $marginTop - $marginBottom
        
        # Find max profit for scaling
        $maxProfit = 1.0
        foreach ($snapshot in $this.ProfitHistory) {
            foreach ($profitValue in $snapshot.Profits.Values) {
                $profVal = [double]$profitValue
                if ($profVal -gt $maxProfit) { $maxProfit = $profVal }
            }
        }
        
        # Draw grid lines
        $gridPen = New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(40, 40, 50), 1)
        for ($i = 0; $i -le 5; $i++) {
            $y = $marginTop + ($graphHeight * $i / 5)
            $g.DrawLine($gridPen, $marginLeft, $y, $marginLeft + $graphWidth, $y)
        }
        for ($i = 0; $i -le 10; $i++) {
            $x = $marginLeft + ($graphWidth * $i / 10)
            $g.DrawLine($gridPen, $x, $marginTop, $x, $marginTop + $graphHeight)
        }
        $gridPen.Dispose()
        
        # Draw axes
        $axisPen = New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(80, 80, 100), 2)
        $axisBottomY = $marginTop + $graphHeight
        $axisRightX = $marginLeft + $graphWidth
        $g.DrawLine($axisPen, $marginLeft, $axisBottomY, $axisRightX, $axisBottomY)
        $g.DrawLine($axisPen, $marginLeft, $marginTop, $marginLeft, $axisBottomY)
        $axisPen.Dispose()
        
        # Draw profit lines for each company
        $historyCount = $this.ProfitHistory.Count
        
        for ($compIdx = 0; $compIdx -lt $this.Market.Companies.Count; $compIdx++) {
            $company = $this.Market.Companies[$compIdx]
            $points = New-Object System.Collections.ArrayList
            
            for ($i = 0; $i -lt $historyCount; $i++) {
                $snapshot = $this.ProfitHistory[$i]
                $profit = [double]$snapshot.Profits[$company.Name]
                
                $divisor = $historyCount - 1
                if ($divisor -le 0) { $divisor = 1 }
                $xFraction = [double]$i / [double]$divisor
                $xPos = $marginLeft + ($xFraction * $graphWidth)
                
                $yFraction = $profit / $maxProfit
                $yOffset = $yFraction * $graphHeight
                $yPos = ($marginTop + $graphHeight) - $yOffset
                
                $point = New-Object System.Drawing.PointF($xPos, $yPos)
                [void]$points.Add($point)
            }
            
            if ($points.Count -gt 1) {
                $color = $this.CompanyColors[$compIdx]
                $pen = New-Object System.Drawing.Pen($color, 3)
                $g.DrawLines($pen, $points.ToArray([System.Drawing.PointF]))
                $pen.Dispose()
            }
        }
        
        # Y-axis labels
        $labelFont = New-Object System.Drawing.Font("Consolas", 9)
        $labelBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Gray)
        
        for ($i = 0; $i -le 5; $i++) {
            $value = $maxProfit * (1 - ($i / 5.0))
            $label = [Math]::Round($value, 1)
            $y = $marginTop + ($graphHeight * $i / 5) - 7
            $g.DrawString("$label", $labelFont, $labelBrush, 10, $y)
        }
        
        $labelFont.Dispose()
        $labelBrush.Dispose()
        
        # Legend (moved to LEFT to avoid overlap with graph)
        $this.DrawGraphLegend($g, 70, $marginTop + $graphHeight + 10)
    }
    
    [void] DrawGraphLegend($g, $x, $y) {
        $font = New-Object System.Drawing.Font("Consolas", 9, [System.Drawing.FontStyle]::Bold)
        $yOffset = 0
        
        for ($i = 0; $i -lt $this.Market.Companies.Count; $i++) {
            $company = $this.Market.Companies[$i]
            $color = $this.CompanyColors[$i]
            
            # Color box
            $brush = New-Object System.Drawing.SolidBrush($color)
            $g.FillRectangle($brush, $x, $y + $yOffset, 15, 15)
            $brush.Dispose()
            
            # Company name + profit
            $profit = [Math]::Round([double]$company.State.Profit, 1)
            $text = "$($company.Name): `$$profit M"
            $textBrush = New-Object System.Drawing.SolidBrush($color)
            $g.DrawString($text, $font, $textBrush, $x + 20, $y + $yOffset)
            $textBrush.Dispose()
            
            $yOffset += 20
        }
        
        $font.Dispose()
    }
    
    [void] DrawDecisionsPanel($sender, $e) {
        $g = $e.Graphics
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 12, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("RECENT DECISIONS", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        if ($this.DecisionHistory.Count -eq 0) { return }
        
        $font = New-Object System.Drawing.Font("Consolas", 9)
        $yPos = 45
        
        # Show last 8 quarters
        $recentDecisions = $this.DecisionHistory | Select-Object -Last 8
        
        foreach ($snapshot in $recentDecisions) {
            $qtr = $snapshot.Quarter
            
            # Quarter label
            $qBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Gray)
            $g.DrawString("Q$qtr", $font, $qBrush, 10, $yPos)
            $qBrush.Dispose()
            
            # Decisions
            $xPos = 50
            foreach ($compName in $snapshot.Decisions.Keys) {
                $decision = $snapshot.Decisions[$compName]
                
                # Color-code by decision type
                $decColor = switch ($decision) {
                    "Invest" { [System.Drawing.Color]::LimeGreen }
                    "Cut" { [System.Drawing.Color]::Red }
                    "Expand" { [System.Drawing.Color]::Cyan }
                    default { [System.Drawing.Color]::Gray }
                }
                
                $decBrush = New-Object System.Drawing.SolidBrush($decColor)
                $g.DrawString($decision.Substring(0, [Math]::Min(3, $decision.Length)), $font, $decBrush, $xPos, $yPos)
                $decBrush.Dispose()
                
                $xPos += 90
            }
            
            $yPos += 18
        }
        
        $font.Dispose()
    }
    
    [void] DrawLearningPanel($sender, $e) {
        $g = $e.Graphics
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 12, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("LEARNING STATS", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        # Agent performance
        $font = New-Object System.Drawing.Font("Consolas", 9)
        $yPos = 45
        
        foreach ($company in $this.Market.Companies) {
            $totalReward = if ($company.PSObject.Properties['TotalReward']) {
                [Math]::Round($company.TotalReward, 1)
            } else { 0 }
            
            $epsilon = if ($company.PSObject.Properties['Agent'] -and 
                          $company.Agent.PSObject.Properties['Epsilon']) {
                [Math]::Round($company.Agent.Epsilon, 3)
            } else { 0 }
            
            # Company name
            $brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
            $g.DrawString("$($company.Name):", $font, $brush, 10, $yPos)
            $brush.Dispose()
            
            # Reward on first line (green)
            $rewardBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::LimeGreen)
            $g.DrawString("R: $totalReward", $font, $rewardBrush, 100, $yPos)
            $rewardBrush.Dispose()
            
            # Move to next line for epsilon
            $yPos += 15
            
            # Epsilon on second line (yellow)
            $epsBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Yellow)
            $g.DrawString("ε: $epsilon", $font, $epsBrush, 100, $yPos)
            $epsBrush.Dispose()
            
            # Space before next company
            $yPos += 20
        }
        
        $font.Dispose()
    }
    
    [void] DrawEventsPanel($sender, $e) {
        $g = $e.Graphics
        
        # Background
        $bgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(20, 20, 25))
        $g.FillRectangle($bgBrush, 0, 0, $sender.Width, $sender.Height)
        $bgBrush.Dispose()
        
        # Title
        $titleFont = New-Object System.Drawing.Font("Consolas", 14, [System.Drawing.FontStyle]::Bold)
        $titleBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Cyan)
        $g.DrawString("EVENT LOG - LIVE FEED", $titleFont, $titleBrush, 10, 10)
        $titleFont.Dispose()
        $titleBrush.Dispose()
        
        # Events
        $font = New-Object System.Drawing.Font("Consolas", 10)
        $yPos = 50
        
        if ($this.EventLog.Count -gt 0) {
            # Show last 6 events
            $lastEvents = $this.EventLog | Select-Object -Last 6
            
            foreach ($event in $lastEvents) {
                # Color-code by event type
                $eventColor = [System.Drawing.Color]::White
                if ($event -match "SURGE|dominates") {
                    $eventColor = [System.Drawing.Color]::LimeGreen
                } elseif ($event -match "DROP|declined") {
                    $eventColor = [System.Drawing.Color]::Red
                } elseif ($event -match "RESET|initialized") {
                    $eventColor = [System.Drawing.Color]::Cyan
                }
                
                $brush = New-Object System.Drawing.SolidBrush($eventColor)
                $g.DrawString($event, $font, $brush, 10, $yPos)
                $brush.Dispose()
                
                $yPos += 18
            }
        } else {
            $msgBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Gray)
            $g.DrawString("No events yet - start simulation to see live updates", $font, $msgBrush, 10, $yPos)
            $msgBrush.Dispose()
        }
        
        $font.Dispose()
    }
    
    # ==================== EXPORT ====================
    
    [void] ExportData() {
        try {
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
            $filename = "market_data_$timestamp.csv"
            
            $csv = "Quarter,Company,Profit,MarketShare`n"
            
            foreach ($snapshot in $this.ProfitHistory) {
                $qtr = $snapshot.Quarter
                foreach ($name in $snapshot.Profits.Keys) {
                    $profit = $snapshot.Profits[$name]
                    $share = $snapshot.MarketShares[$name]
                    $csv += "$qtr,$name,$profit,$share`n"
                }
            }
            
            $csv | Out-File -FilePath $filename -Encoding UTF8
            
            [System.Windows.Forms.MessageBox]::Show(
                "Data exported successfully!`n`nFile: $filename`nRows: $($this.ProfitHistory.Count * 4)", 
                "Export Complete",
                [System.Windows.Forms.MessageBoxButtons]::OK,
                [System.Windows.Forms.MessageBoxIcon]::Information
            )
            
            Write-Host "💾 Data exported to: $filename" -ForegroundColor Green
            
        } catch {
            [System.Windows.Forms.MessageBox]::Show(
                "Export failed: $_", 
                "Export Error",
                [System.Windows.Forms.MessageBoxButtons]::OK,
                [System.Windows.Forms.MessageBoxIcon]::Error
            )
        }
    }
    
    # ==================== SHOW ====================
    
    [void] Show() {
        $this.Form.ShowDialog()
    }
}