import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card } from '../components/common/Card'; import { Button } from '../components/common/Button'; import { Download, FileText, RefreshCw, Sparkles, Loader2, AlertTriangle, CheckCircle, Copy, Trophy, TrendingUp, FileJson, FileSpreadsheet, Settings, ArrowRight, ChevronDown, ChevronUp, Printer } from 'lucide-react'; import { apiClient } from '../api/client'; import { useStudy } from '../context/StudyContext'; import { MarkdownRenderer } from '../components/MarkdownRenderer'; interface BestSolution { best_trial: { trial_number: number; objective: number; design_variables: Record; user_attrs?: Record; timestamp?: string; } | null; first_trial: { trial_number: number; objective: number; design_variables: Record; } | null; improvements: Record; total_trials: number; } export default function Results() { const { selectedStudy, isInitialized } = useStudy(); const navigate = useNavigate(); const [reportContent, setReportContent] = useState(null); const [loading, setLoading] = useState(false); const [generating, setGenerating] = useState(false); const [error, setError] = useState(null); const [copied, setCopied] = useState(false); const [lastGenerated, setLastGenerated] = useState(null); const [bestSolution, setBestSolution] = useState(null); const [showAllParams, setShowAllParams] = useState(false); const [exporting, setExporting] = useState(null); // Redirect if no study selected (but only after initialization completes) useEffect(() => { if (isInitialized && !selectedStudy) { navigate('/'); } }, [selectedStudy, navigate, isInitialized]); // Load report and best solution when study changes useEffect(() => { if (selectedStudy) { loadReport(); loadBestSolution(); } }, [selectedStudy]); // Show loading state while initializing (must be after all hooks) if (!isInitialized) { return (

Loading study...

); } const loadReport = async () => { if (!selectedStudy) return; setLoading(true); setError(null); try { const data = await apiClient.getStudyReport(selectedStudy.id); setReportContent(data.content); if (data.generated_at) { setLastGenerated(data.generated_at); } } catch { // No report yet - show placeholder setReportContent(null); } finally { setLoading(false); } }; const loadBestSolution = async () => { if (!selectedStudy) return; try { const data = await apiClient.getBestSolution(selectedStudy.id); setBestSolution(data); } catch { setBestSolution(null); } }; const handleGenerate = async () => { if (!selectedStudy) return; setGenerating(true); setError(null); try { const data = await apiClient.generateReport(selectedStudy.id); setReportContent(data.content); if (data.generated_at) { setLastGenerated(data.generated_at); } } catch (err: any) { setError(err.message || 'Failed to generate report'); } finally { setGenerating(false); } }; const handleCopy = async () => { if (reportContent) { await navigator.clipboard.writeText(reportContent); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; const handleDownload = () => { if (!reportContent || !selectedStudy) return; const blob = new Blob([reportContent], { type: 'text/markdown' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${selectedStudy.id}_report.md`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handlePrintPDF = () => { if (!reportContent || !selectedStudy) return; // Create a printable version of the report const printWindow = window.open('', '_blank'); if (!printWindow) { setError('Pop-up blocked. Please allow pop-ups to print PDF.'); return; } printWindow.document.write(` ${selectedStudy.name} - Optimization Report
Study: ${selectedStudy.name}
Generated: ${new Date().toLocaleString()}
Trials: ${selectedStudy.progress.current} / ${selectedStudy.progress.total}
${convertMarkdownToHTML(reportContent)} `); printWindow.document.close(); // Wait for content to load then print printWindow.onload = () => { printWindow.print(); }; }; // Simple markdown to HTML converter for print const convertMarkdownToHTML = (md: string): string => { return md // Headers .replace(/^### (.*$)/gm, '

$1

') .replace(/^## (.*$)/gm, '

$1

') .replace(/^# (.*$)/gm, '

$1

') // Bold and italic .replace(/\*\*\*(.*?)\*\*\*/g, '$1') .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/\*(.*?)\*/g, '$1') // Code blocks .replace(/```(\w*)\n([\s\S]*?)```/g, '
$2
') .replace(/`([^`]+)`/g, '$1') // Lists .replace(/^\s*[-*]\s+(.*)$/gm, '
  • $1
  • ') .replace(/(
  • .*<\/li>)\n(?!
  • )/g, '$1\n') .replace(/(?)(
  • )/g, '
      $1') // Blockquotes .replace(/^>\s*(.*)$/gm, '
      $1
      ') // Horizontal rules .replace(/^---$/gm, '
      ') // Paragraphs .replace(/\n\n/g, '

      ') .replace(/^(.+)$/gm, (match) => { if (match.startsWith('<')) return match; return match; }); }; const handleExport = async (format: 'csv' | 'json' | 'config') => { if (!selectedStudy) return; setExporting(format); try { const data = await apiClient.exportData(selectedStudy.id, format); if (data.filename && data.content) { const blob = new Blob([data.content], { type: data.content_type || 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = data.filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } else if (format === 'json' && data.trials) { // Direct JSON response const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${selectedStudy.id}_data.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } } catch (err: any) { setError(err.message || `Failed to export ${format}`); } finally { setExporting(null); } }; if (!selectedStudy) { return null; } const paramEntries = bestSolution?.best_trial?.design_variables ? Object.entries(bestSolution.best_trial.design_variables) : []; const visibleParams = showAllParams ? paramEntries : paramEntries.slice(0, 6); return (

      {/* Header */}

      Results

      {selectedStudy.name}

      {reportContent && ( <> )}
      {/* Error Message */} {error && (
      {error}
      )} {/* Best Solution Card */} {bestSolution?.best_trial && (

      Best Solution

      Trial #{bestSolution.best_trial.trial_number} of {bestSolution.total_trials}

      {bestSolution.improvements.objective && (
      {bestSolution.improvements.objective.improvement_pct > 0 ? '+' : ''} {bestSolution.improvements.objective.improvement_pct.toFixed(1)}% improvement
      )}
      {/* Objective Value */}
      Best Objective
      {bestSolution.best_trial.objective.toExponential(4)}
      {bestSolution.first_trial && (
      Initial Value
      {bestSolution.first_trial.objective.toExponential(4)}
      )} {bestSolution.improvements.objective && (
      Absolute Change
      {bestSolution.improvements.objective.absolute_change.toExponential(4)}
      )}
      {/* Design Variables */}

      Optimal Design Variables

      {paramEntries.length > 6 && ( )}
      {visibleParams.map(([name, value]) => (
      {name}
      {typeof value === 'number' ? value.toFixed(4) : value}
      ))}
      )} {/* Export Options */}

      Export Data

      {/* Main Content - Report */}

      Report Content

      {lastGenerated && ( Last generated: {new Date(lastGenerated).toLocaleString()} )}
      {loading ? (
      Loading report...
      ) : reportContent ? (
      ) : (

      No Report Generated

      Click "Generate Report" to create an AI-generated analysis of your optimization results.

      )}
      {/* Study Stats */}
      Total Trials
      {selectedStudy.progress.current}
      Best Value
      {selectedStudy.best_value?.toFixed(4) || 'N/A'}
      Target
      {selectedStudy.target?.toFixed(4) || 'N/A'}
      Status
      {selectedStudy.status}
      ); }