/**
 * Training Metrics Component
 *
 * Real-time visualization of training progress with loss curves and metrics.
 * Supports SSE (Server-Sent Events) for live updates during LoRA fine-tuning.
 *
 * Phase 3.3: Training Dashboard with Live Metrics
 */

'use client'

import { useState, useEffect, useCallback, useRef } from 'react'

// Training data point for charts
interface TrainingDataPoint {
  epoch: number
  step: number
  loss: number
  val_loss?: number
  learning_rate: number
  timestamp: number
}

// Training job status
interface TrainingStatus {
  job_id: string
  status: 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'
  progress: number // 0-100
  current_epoch: number
  total_epochs: number
  current_step: number
  total_steps: number
  elapsed_time_ms: number
  estimated_remaining_ms: number
  metrics: {
    loss: number
    val_loss?: number
    accuracy?: number
    learning_rate: number
  }
  history: TrainingDataPoint[]
  error?: string
}

interface TrainingMetricsProps {
  /** API base URL */
  apiBase: string
  /** Job ID to track (null for simulation mode) */
  jobId?: string | null
  /** Simulate training progress for demo */
  simulateMode?: boolean
  /** Custom class names */
  className?: string
  /** Callback when training completes */
  onComplete?: (status: TrainingStatus) => void
  /** Callback on error */
  onError?: (error: string) => void
}

/**
 * Custom hook for SSE-based training metrics
 */
export function useTrainingMetricsSSE(
  apiBase: string,
  jobId: string | null,
  onUpdate?: (status: TrainingStatus) => void
) {
  const [status, setStatus] = useState<TrainingStatus | null>(null)
  const [connected, setConnected] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const eventSourceRef = useRef<EventSource | null>(null)

  useEffect(() => {
    if (!jobId) return

    const url = `${apiBase}/api/klausur/trocr/training/metrics/stream?job_id=${jobId}`
    const eventSource = new EventSource(url)
    eventSourceRef.current = eventSource

    eventSource.onopen = () => {
      setConnected(true)
      setError(null)
    }

    eventSource.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data) as TrainingStatus
        setStatus(data)
        onUpdate?.(data)

        // Close connection when training is done
        if (data.status === 'completed' || data.status === 'failed' || data.status === 'cancelled') {
          eventSource.close()
          setConnected(false)
        }
      } catch (e) {
        console.error('Failed to parse SSE message:', e)
      }
    }

    eventSource.onerror = () => {
      setError('Verbindung zum Server verloren')
      setConnected(false)
      eventSource.close()
    }

    return () => {
      eventSource.close()
      setConnected(false)
    }
  }, [apiBase, jobId, onUpdate])

  const disconnect = useCallback(() => {
    eventSourceRef.current?.close()
    setConnected(false)
  }, [])

  return { status, connected, error, disconnect }
}

/**
 * Simple line chart component for loss visualization
 */
function LossChart({
  data,
  height = 200,
  className = ''
}: {
  data: TrainingDataPoint[]
  height?: number
  className?: string
}) {
  if (data.length === 0) {
    return (
      <div className={`flex items-center justify-center bg-slate-50 rounded-lg ${className}`} style={{ height }}>
        <span className="text-slate-400 text-sm">Keine Daten</span>
      </div>
    )
  }

  // Calculate bounds
  const losses = data.map(d => d.loss)
  const valLosses = data.filter(d => d.val_loss !== undefined).map(d => d.val_loss!)
  const allLosses = [...losses, ...valLosses]
  const minLoss = Math.min(...allLosses) * 0.9
  const maxLoss = Math.max(...allLosses) * 1.1
  const lossRange = maxLoss - minLoss || 1

  // SVG dimensions
  const width = 400
  const padding = { top: 20, right: 20, bottom: 30, left: 50 }
  const chartWidth = width - padding.left - padding.right
  const chartHeight = height - padding.top - padding.bottom

  // Generate path for loss line
  const generatePath = (values: number[]) => {
    if (values.length === 0) return ''
    return values
      .map((loss, idx) => {
        const x = padding.left + (idx / (values.length - 1 || 1)) * chartWidth
        const y = padding.top + chartHeight - ((loss - minLoss) / lossRange) * chartHeight
        return `${idx === 0 ? 'M' : 'L'} ${x} ${y}`
      })
      .join(' ')
  }

  const lossPath = generatePath(losses)
  const valLossPath = valLosses.length > 0 ? generatePath(valLosses) : ''

  // Y-axis labels
  const yLabels = [maxLoss, (maxLoss + minLoss) / 2, minLoss].map(v => v.toFixed(3))

  return (
    <svg viewBox={`0 0 ${width} ${height}`} className={`w-full ${className}`} preserveAspectRatio="xMidYMid meet">
      {/* Grid lines */}
      {[0, 0.5, 1].map((ratio, idx) => (
        <line
          key={idx}
          x1={padding.left}
          y1={padding.top + chartHeight * ratio}
          x2={width - padding.right}
          y2={padding.top + chartHeight * ratio}
          stroke="#e2e8f0"
          strokeWidth="1"
        />
      ))}

      {/* Y-axis labels */}
      {yLabels.map((label, idx) => (
        <text
          key={idx}
          x={padding.left - 5}
          y={padding.top + (idx / 2) * chartHeight + 4}
          textAnchor="end"
          className="fill-slate-500 text-xs"
        >
          {label}
        </text>
      ))}

      {/* X-axis label */}
      <text
        x={width / 2}
        y={height - 5}
        textAnchor="middle"
        className="fill-slate-500 text-xs"
      >
        Epoche / Schritt
      </text>

      {/* Y-axis label */}
      <text
        x={12}
        y={height / 2}
        textAnchor="middle"
        className="fill-slate-500 text-xs"
        transform={`rotate(-90, 12, ${height / 2})`}
      >
        Loss
      </text>

      {/* Training loss line */}
      <path
        d={lossPath}
        fill="none"
        stroke="#8b5cf6"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />

      {/* Validation loss line (dashed) */}
      {valLossPath && (
        <path
          d={valLossPath}
          fill="none"
          stroke="#22c55e"
          strokeWidth="2"
          strokeDasharray="5,5"
          strokeLinecap="round"
          strokeLinejoin="round"
        />
      )}

      {/* Data points */}
      {data.map((point, idx) => {
        const x = padding.left + (idx / (data.length - 1 || 1)) * chartWidth
        const y = padding.top + chartHeight - ((point.loss - minLoss) / lossRange) * chartHeight
        return (
          <circle
            key={idx}
            cx={x}
            cy={y}
            r="3"
            fill="#8b5cf6"
            className="hover:r-4 transition-all"
          >
            <title>Epoch {point.epoch}, Step {point.step}: {point.loss.toFixed(4)}</title>
          </circle>
        )
      })}

      {/* Legend */}
      <g transform={`translate(${padding.left}, ${height - 25})`}>
        <line x1="0" y1="0" x2="20" y2="0" stroke="#8b5cf6" strokeWidth="2" />
        <text x="25" y="4" className="fill-slate-600 text-xs">Training Loss</text>

        {valLossPath && (
          <>
            <line x1="120" y1="0" x2="140" y2="0" stroke="#22c55e" strokeWidth="2" strokeDasharray="5,5" />
            <text x="145" y="4" className="fill-slate-600 text-xs">Val Loss</text>
          </>
        )}
      </g>
    </svg>
  )
}

/**
 * Progress ring component
 */
function ProgressRing({
  progress,
  size = 80,
  strokeWidth = 6,
  className = ''
}: {
  progress: number
  size?: number
  strokeWidth?: number
  className?: string
}) {
  const radius = (size - strokeWidth) / 2
  const circumference = radius * 2 * Math.PI
  const offset = circumference - (progress / 100) * circumference

  return (
    <svg width={size} height={size} className={className}>
      {/* Background circle */}
      <circle
        cx={size / 2}
        cy={size / 2}
        r={radius}
        fill="none"
        stroke="#e2e8f0"
        strokeWidth={strokeWidth}
      />
      {/* Progress circle */}
      <circle
        cx={size / 2}
        cy={size / 2}
        r={radius}
        fill="none"
        stroke="#8b5cf6"
        strokeWidth={strokeWidth}
        strokeDasharray={circumference}
        strokeDashoffset={offset}
        strokeLinecap="round"
        transform={`rotate(-90 ${size / 2} ${size / 2})`}
        className="transition-all duration-300"
      />
      {/* Center text */}
      <text
        x={size / 2}
        y={size / 2}
        textAnchor="middle"
        dominantBaseline="middle"
        className="fill-slate-900 font-bold text-lg"
      >
        {progress.toFixed(0)}%
      </text>
    </svg>
  )
}

/**
 * Format time duration
 */
function formatDuration(ms: number): string {
  if (ms < 1000) return `${ms}ms`
  const seconds = Math.floor(ms / 1000)
  if (seconds < 60) return `${seconds}s`
  const minutes = Math.floor(seconds / 60)
  const remainingSeconds = seconds % 60
  if (minutes < 60) return `${minutes}m ${remainingSeconds}s`
  const hours = Math.floor(minutes / 60)
  const remainingMinutes = minutes % 60
  return `${hours}h ${remainingMinutes}m`
}

/**
 * Training Metrics Component - Full Dashboard
 */
export function TrainingMetrics({
  apiBase,
  jobId = null,
  simulateMode = false,
  className = '',
  onComplete,
  onError
}: TrainingMetricsProps) {
  const [status, setStatus] = useState<TrainingStatus | null>(null)
  const [simulationInterval, setSimulationInterval] = useState<NodeJS.Timeout | null>(null)

  // SSE hook for real connection
  const { status: sseStatus, connected, error } = useTrainingMetricsSSE(
    apiBase,
    simulateMode ? null : jobId,
    (newStatus) => {
      if (newStatus.status === 'completed') {
        onComplete?.(newStatus)
      } else if (newStatus.status === 'failed' && newStatus.error) {
        onError?.(newStatus.error)
      }
    }
  )

  // Use SSE status if available
  useEffect(() => {
    if (sseStatus) {
      setStatus(sseStatus)
    }
  }, [sseStatus])

  // Simulation mode for demo
  useEffect(() => {
    if (!simulateMode) return

    let step = 0
    const totalSteps = 100
    const history: TrainingDataPoint[] = []

    const interval = setInterval(() => {
      step++
      const epoch = Math.floor((step / totalSteps) * 3) + 1
      const progress = (step / totalSteps) * 100

      // Simulate decreasing loss with noise
      const baseLoss = 2.5 * Math.exp(-step / 30) + 0.1
      const noise = (Math.random() - 0.5) * 0.1
      const loss = Math.max(0.05, baseLoss + noise)

      const dataPoint: TrainingDataPoint = {
        epoch,
        step,
        loss,
        val_loss: step % 10 === 0 ? loss * (1 + Math.random() * 0.2) : undefined,
        learning_rate: 0.00005 * Math.pow(0.95, epoch - 1),
        timestamp: Date.now()
      }
      history.push(dataPoint)

      const newStatus: TrainingStatus = {
        job_id: 'simulation',
        status: step >= totalSteps ? 'completed' : 'running',
        progress,
        current_epoch: epoch,
        total_epochs: 3,
        current_step: step,
        total_steps: totalSteps,
        elapsed_time_ms: step * 500,
        estimated_remaining_ms: (totalSteps - step) * 500,
        metrics: {
          loss,
          val_loss: dataPoint.val_loss,
          accuracy: 0.7 + (step / totalSteps) * 0.25,
          learning_rate: dataPoint.learning_rate
        },
        history: [...history]
      }

      setStatus(newStatus)

      if (step >= totalSteps) {
        clearInterval(interval)
        onComplete?.(newStatus)
      }
    }, 500)

    setSimulationInterval(interval)

    return () => {
      clearInterval(interval)
    }
  }, [simulateMode, onComplete])

  // Stop simulation
  const stopSimulation = () => {
    if (simulationInterval) {
      clearInterval(simulationInterval)
      setSimulationInterval(null)
    }
  }

  if (error) {
    return (
      <div className={`bg-red-50 border border-red-200 rounded-xl p-6 ${className}`}>
        <div className="flex items-center gap-3 text-red-700">
          <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
          </svg>
          <span>{error}</span>
        </div>
      </div>
    )
  }

  if (!status) {
    return (
      <div className={`bg-slate-50 rounded-xl p-6 ${className}`}>
        <div className="flex items-center justify-center gap-3 text-slate-500">
          <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-purple-600"></div>
          <span>Warte auf Training-Daten...</span>
        </div>
      </div>
    )
  }

  return (
    <div className={`bg-white rounded-xl shadow-sm border ${className}`}>
      {/* Header */}
      <div className="flex items-center justify-between p-4 border-b">
        <div className="flex items-center gap-3">
          <h3 className="text-lg font-semibold text-slate-900">Training Dashboard</h3>
          <div className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${
            status.status === 'running' ? 'bg-blue-100 text-blue-700' :
            status.status === 'completed' ? 'bg-green-100 text-green-700' :
            status.status === 'failed' ? 'bg-red-100 text-red-700' :
            'bg-slate-100 text-slate-700'
          }`}>
            {status.status === 'running' && (
              <span className="w-2 h-2 rounded-full bg-blue-500 animate-pulse"></span>
            )}
            {status.status === 'running' ? 'Laeuft' :
             status.status === 'completed' ? 'Abgeschlossen' :
             status.status === 'failed' ? 'Fehlgeschlagen' :
             status.status}
          </div>
          {connected && (
            <span className="text-xs text-green-600 flex items-center gap-1">
              <span className="w-1.5 h-1.5 rounded-full bg-green-500"></span>
              Live
            </span>
          )}
        </div>
        {simulateMode && status.status === 'running' && (
          <button
            onClick={stopSimulation}
            className="px-3 py-1 text-sm bg-slate-200 hover:bg-slate-300 text-slate-700 rounded transition-colors"
          >
            Stoppen
          </button>
        )}
      </div>

      {/* Main content */}
      <div className="p-4 grid grid-cols-1 lg:grid-cols-3 gap-6">
        {/* Progress section */}
        <div className="flex flex-col items-center justify-center gap-4">
          <ProgressRing progress={status.progress} size={120} strokeWidth={8} />
          <div className="text-center">
            <div className="text-sm text-slate-500">
              Epoche {status.current_epoch} / {status.total_epochs}
            </div>
            <div className="text-xs text-slate-400">
              Schritt {status.current_step} / {status.total_steps}
            </div>
          </div>
        </div>

        {/* Loss chart */}
        <div className="lg:col-span-2">
          <h4 className="text-sm font-medium text-slate-700 mb-2">Loss-Verlauf</h4>
          <LossChart data={status.history} height={180} />
        </div>
      </div>

      {/* Metrics grid */}
      <div className="px-4 pb-4 grid grid-cols-2 md:grid-cols-4 gap-3">
        <div className="bg-slate-50 rounded-lg p-3 text-center">
          <div className="text-lg font-bold text-slate-900">{status.metrics.loss.toFixed(4)}</div>
          <div className="text-xs text-slate-500">Aktueller Loss</div>
        </div>
        {status.metrics.val_loss !== undefined && (
          <div className="bg-slate-50 rounded-lg p-3 text-center">
            <div className="text-lg font-bold text-slate-900">{status.metrics.val_loss.toFixed(4)}</div>
            <div className="text-xs text-slate-500">Validation Loss</div>
          </div>
        )}
        {status.metrics.accuracy !== undefined && (
          <div className="bg-green-50 rounded-lg p-3 text-center">
            <div className="text-lg font-bold text-green-700">{(status.metrics.accuracy * 100).toFixed(1)}%</div>
            <div className="text-xs text-slate-500">Genauigkeit</div>
          </div>
        )}
        <div className="bg-slate-50 rounded-lg p-3 text-center">
          <div className="text-lg font-bold text-slate-900">{status.metrics.learning_rate.toExponential(1)}</div>
          <div className="text-xs text-slate-500">Learning Rate</div>
        </div>
      </div>

      {/* Time info */}
      <div className="px-4 pb-4 flex items-center justify-between text-sm text-slate-500">
        <div>Vergangen: {formatDuration(status.elapsed_time_ms)}</div>
        {status.status === 'running' && (
          <div>Geschaetzt: {formatDuration(status.estimated_remaining_ms)} verbleibend</div>
        )}
      </div>
    </div>
  )
}

/**
 * Compact Training Metrics for inline display
 */
export function TrainingMetricsCompact({
  progress,
  currentEpoch,
  totalEpochs,
  loss,
  status,
  className = ''
}: {
  progress: number
  currentEpoch: number
  totalEpochs: number
  loss: number
  status: 'running' | 'completed' | 'failed'
  className?: string
}) {
  return (
    <div className={`flex items-center gap-4 ${className}`}>
      <ProgressRing progress={progress} size={48} strokeWidth={4} />
      <div className="flex-1">
        <div className="flex items-center gap-2 text-sm">
          <span className="font-medium text-slate-900">Epoche {currentEpoch}/{totalEpochs}</span>
          <span className={`px-2 py-0.5 rounded-full text-xs ${
            status === 'running' ? 'bg-blue-100 text-blue-700' :
            status === 'completed' ? 'bg-green-100 text-green-700' :
            'bg-red-100 text-red-700'
          }`}>
            {status === 'running' ? 'Laeuft' : status === 'completed' ? 'Fertig' : 'Fehler'}
          </span>
        </div>
        <div className="text-xs text-slate-500 mt-1">
          Loss: {loss.toFixed(4)}
        </div>
      </div>
    </div>
  )
}

export default TrainingMetrics
