"use client"; import { useState } from "react"; import { RotateCcw, Play, Pause, Send, ChevronDown, Download, Zap, ShieldX, Activity } from "lucide-react"; import { cn } from "@/lib/utils"; import { Tooltip, SignalTooltip } from "@/components/ui/Tooltip"; import type { AEPOAction, TaskDifficulty, ActionLogEntry } from "@/lib/types"; interface ControlPanelProps { onReset: (task: TaskDifficulty) => void; onStep: (action: AEPOAction) => void; isResetting: boolean; isRunning: boolean; onToggleAutoRun: () => void; episodeActive: boolean; autoRunInterval: number; onIntervalChange: (ms: number) => void; actionLog: ActionLogEntry[]; } const TASK_OPTIONS: { value: TaskDifficulty; label: string; color: string }[] = [ { value: "easy", label: "Easy", color: "text-green-400" }, { value: "medium", label: "Medium", color: "text-yellow-400" }, { value: "hard", label: "Hard", color: "text-red-400" }, ]; const SPEED_OPTIONS = [ { label: "Slow", ms: 1200 }, { label: "Normal", ms: 600 }, { label: "Fast", ms: 200 }, { label: "Turbo", ms: 50 }, ]; const SCENARIO_PRESETS: { label: string; icon: React.ReactNode; action: AEPOAction; description: string; color: string }[] = [ { label: "Kafka Crisis", icon: , description: "CircuitBreaker + FailFast — sheds kafka lag fastest", color: "border-red-500/40 text-red-400 bg-red-500/10 hover:bg-red-500/20", action: { risk_decision: 1, crypto_verify: 1, infra_routing: 2, db_retry_policy: 0, settlement_policy: 1, app_priority: 2 }, }, { label: "Fraud Spike", icon: , description: "Reject + FullVerify — max fraud defense", color: "border-orange-500/40 text-orange-400 bg-orange-500/10 hover:bg-orange-500/20", action: { risk_decision: 1, crypto_verify: 0, infra_routing: 0, db_retry_policy: 0, settlement_policy: 0, app_priority: 2 }, }, { label: "SLA Recovery", icon: , description: "Approve + Throttle — reduces P99 without full CB", color: "border-cyan-500/40 text-cyan-400 bg-cyan-500/10 hover:bg-cyan-500/20", action: { risk_decision: 0, crypto_verify: 1, infra_routing: 1, db_retry_policy: 0, settlement_policy: 1, app_priority: 2 }, }, ]; const ACTION_FIELDS: { key: keyof AEPOAction; label: string; options: { value: number; label: string }[]; tooltip: string; }[] = [ { key: "risk_decision", label: "Risk Decision", tooltip: "Core reward driver. Approve on low-risk = +0.8. Reject on high-risk = +0.8. Mismatch = -0.3.", options: [{ value: 0, label: "0 · Approve" }, { value: 1, label: "1 · Reject" }, { value: 2, label: "2 · Challenge" }], }, { key: "crypto_verify", label: "Crypto Verify", tooltip: "FullVerify adds latency but is safe. SkipVerify is faster but gives -0.3 if risk_score > 50.", options: [{ value: 0, label: "0 · FullVerify" }, { value: 1, label: "1 · SkipVerify" }], }, { key: "infra_routing", label: "Infra Routing", tooltip: "Normal = default throughput. Throttle = reduces kafka lag slowly. CircuitBreaker = fastest lag reduction, -0.1 throughput penalty.", options: [{ value: 0, label: "0 · Normal" }, { value: 1, label: "1 · Throttle" }, { value: 2, label: "2 · CircuitBreaker" }], }, { key: "db_retry_policy", label: "DB Retry", tooltip: "FailFast = default, no penalty. ExpBackoff = -0.10 penalty but stabilizes DB pool when usage > 80%.", options: [{ value: 0, label: "0 · FailFast" }, { value: 1, label: "1 · ExpBackoff" }], }, { key: "settlement_policy", label: "Settlement", tooltip: "StandardSync = default. DeferredAsync = +0.05 bonus when bank sim status is Degraded.", options: [{ value: 0, label: "0 · StandardSync" }, { value: 1, label: "1 · DeferredAsync" }], }, { key: "app_priority", label: "App Priority", tooltip: "Match to merchant tier for +0.02/step bonus. Enterprise → UPI. Small → Balanced.", options: [{ value: 0, label: "0 · UPI" }, { value: 1, label: "1 · Credit" }, { value: 2, label: "2 · Balanced" }], }, ]; const DEFAULT_ACTION: AEPOAction = { risk_decision: 0, crypto_verify: 0, infra_routing: 0, db_retry_policy: 0, settlement_policy: 0, app_priority: 2, }; function exportCSV(log: ActionLogEntry[]) { if (log.length === 0) return; const headers = ["step", "timestamp", "phase", "reward", "risk_decision", "crypto_verify", "infra_routing", "db_retry_policy", "settlement_policy", "app_priority"]; const rows = log.map((e) => [ e.step, e.timestamp, e.phase, e.reward.toFixed(4), e.action.risk_decision, e.action.crypto_verify, e.action.infra_routing, e.action.db_retry_policy, e.action.settlement_policy, e.action.app_priority, ].join(",")); const csv = [headers.join(","), ...rows.reverse()].join("\n"); const blob = new Blob([csv], { type: "text/csv" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `aepo_episode_${Date.now()}.csv`; a.click(); URL.revokeObjectURL(url); } export function ControlPanel({ onReset, onStep, isResetting, isRunning, onToggleAutoRun, episodeActive, autoRunInterval, onIntervalChange, actionLog, }: ControlPanelProps) { const [task, setTask] = useState("easy"); const [action, setAction] = useState(DEFAULT_ACTION); return (

Control Panel · Manual Override

{/* Row 1: Reset + Auto Run + Speed */}
{/* Speed selector */}
Speed: {SPEED_OPTIONS.map((opt) => ( ))}
{/* Export CSV */}
{/* Row 2: Scenario Presets */}
Stress presets: {SCENARIO_PRESETS.map((preset) => ( ))}
{/* 6-dim action form */}
{ACTION_FIELDS.map((field) => (
))}
{/* Send button + preview */}
payload: [{action.risk_decision},{action.crypto_verify},{action.infra_routing}, {action.db_retry_policy},{action.settlement_policy},{action.app_priority}]
); }