/**
 * RunTracingPanel
 *
 * Shows AutoStepLog entries for a workflow run with live SSE push.
 * Falls back to polling if SSE connection fails.
 * Displays per-node status, timing, I/O snapshots, and retry info.
 */
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useApiRequest } from '../../../hooks/useApi';
import type { AutoStepLog } from '../../../api/workflowApi';

import { useLanguage } from '../../../providers/language/LanguageContext';

interface RunTracingPanelProps {
  instanceId: string;
  runId: string | null;
  onNodeSelect?: (nodeId: string) => void;
  onActiveStepsChange?: (nodeStatuses: Record<string, string>) => void;
}

const STATUS_COLORS: Record<string, string> = {
  pending: '#999',
  running: '#f0ad4e',
  completed: '#28a745',
  failed: '#dc3545',
  skipped: '#6c757d',
};

const STATUS_ICONS: Record<string, string> = {
  pending: '○',
  running: '◉',
  completed: '✓',
  failed: '✗',
  skipped: '—',
};

function _formatTimestamp(ts: number | string | null | undefined): string {
  if (!ts) return '';
  const d = typeof ts === 'number' ? new Date(ts * 1000) : new Date(ts);
  if (isNaN(d.getTime())) return '';
  return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}

function _truncateJson(obj: unknown, maxLen = 300): string {
  if (!obj || (typeof obj === 'object' && Object.keys(obj as object).length === 0)) return '';
  try {
    const s = JSON.stringify(obj, null, 2);
    return s.length > maxLen ? s.slice(0, maxLen) + '\n...' : s;
  } catch {
    return String(obj);
  }
}

const CollapsibleSection: React.FC<{
  label: string; content: string;
}> = ({ label, content }) => {
  const [open, setOpen] = useState(false);
  if (!content) return null;
  return (
    <div style={{ marginTop: '4px' }}>
      <button
        onClick={(e) => { e.stopPropagation(); setOpen(!open); }}
        style={{
          background: 'none', border: 'none', cursor: 'pointer', padding: 0,
          color: 'var(--text-link, #0969da)', fontSize: '11px', textDecoration: 'underline',
        }}
      >
        {open ? '▾' : '▸'} {label}
      </button>
      {open && (
        <pre style={{
          margin: '4px 0 0', padding: '6px', borderRadius: '4px',
          background: 'var(--bg-secondary, #f6f8fa)', fontSize: '11px',
          whiteSpace: 'pre-wrap', wordBreak: 'break-all', maxHeight: '200px', overflowY: 'auto',
        }}>
          {content}
        </pre>
      )}
    </div>
  );
};

export const RunTracingPanel: React.FC<RunTracingPanelProps> = ({
  instanceId,
  runId,
  onNodeSelect,
  onActiveStepsChange,
}) => {
  const { t } = useLanguage();
  const [steps, setSteps] = useState<AutoStepLog[]>([]);
  const [loading, setLoading] = useState(false);
  const [sseConnected, setSseConnected] = useState(false);
  const eventSourceRef = useRef<EventSource | null>(null);
  const { request } = useApiRequest();

  const loadSteps = useCallback(async () => {
    if (!runId || !instanceId) return;
    setLoading(true);
    try {
      const data = await request({
        url: `/api/workflows/${instanceId}/runs/${runId}/steps`,
        method: 'get',
      });
      setSteps(data?.steps || []);
    } catch (e) {
      console.error('[RunTracing] Failed to load steps:', e);
    } finally {
      setLoading(false);
    }
  }, [runId, instanceId, request]);

  // SSE live-push connection
  useEffect(() => {
    if (!runId || !instanceId) return;
    loadSteps();

    const url = `/api/workflows/${instanceId}/runs/${runId}/stream`;
    const es = new EventSource(url);
    eventSourceRef.current = es;

    es.onopen = () => setSseConnected(true);
    es.onmessage = (event) => {
      try {
        const payload = JSON.parse(event.data);
        if (payload.type === 'keepalive') return;
        if (payload.type === 'run_complete' || payload.type === 'run_failed') {
          loadSteps();
          es.close();
          setSseConnected(false);
          return;
        }
        if (payload.status === 'running') {
          setSteps((prev) => {
            const exists = prev.some((s) => s.id === payload.id);
            if (exists) return prev.map((s) => s.id === payload.id ? { ...s, ...payload } : s);
            return [...prev, payload as AutoStepLog];
          });
        } else {
          setSteps((prev) => prev.map((s) => s.id === payload.id ? { ...s, ...payload } : s));
        }
      } catch { /* ignore parse errors */ }
    };
    es.onerror = () => {
      setSseConnected(false);
      es.close();
    };

    return () => {
      es.close();
      eventSourceRef.current = null;
      setSseConnected(false);
    };
  }, [runId, instanceId]); // eslint-disable-line react-hooks/exhaustive-deps

  // Fallback polling when SSE is not connected
  useEffect(() => {
    if (sseConnected || !runId || !instanceId) return;
    const interval = setInterval(loadSteps, 3000);
    return () => clearInterval(interval);
  }, [sseConnected, runId, instanceId, loadSteps]);

  // Emit active node statuses for canvas highlighting
  useEffect(() => {
    if (!onActiveStepsChange) return;
    const nodeStatuses: Record<string, string> = {};
    for (const step of steps) {
      nodeStatuses[step.nodeId] = step.status;
    }
    onActiveStepsChange(nodeStatuses);
  }, [steps, onActiveStepsChange]);

  if (!runId) {
    return (
      <div style={{ padding: '16px', color: 'var(--text-secondary, #888)', fontSize: '13px' }}>
        {t('Run auswählen, um Tracing-Details zu sehen.')}
      </div>
    );
  }

  return (
    <div style={{ padding: '12px', overflowY: 'auto', height: '100%' }}>
      <div style={{ fontWeight: 600, fontSize: '14px', marginBottom: '12px' }}>
        {t('Run-Schritte')}{' '}
        {loading && (
          <span style={{ fontWeight: 400, fontSize: '12px', color: '#888' }}>({t('wird geladen…')})</span>
        )}
      </div>
      {steps.length === 0 && !loading && (
        <div style={{ color: 'var(--text-secondary, #888)', fontSize: '13px' }}>{t('Noch keine Schritte aufgezeichnet')}</div>
      )}
      {steps.map((step: any) => {
        const startStr = _formatTimestamp(step.startedAt);
        const endStr = _formatTimestamp(step.completedAt);
        const inputStr = _truncateJson(step.inputSnapshot);
        const outputStr = _truncateJson(step.output);
        const isLoop = step.inputSnapshot?._loopIndex != null;

        return (
          <div
            key={step.id}
            onClick={() => onNodeSelect?.(step.nodeId)}
            style={{
              padding: '8px 12px',
              marginBottom: '6px',
              borderRadius: '6px',
              border: `1px solid ${STATUS_COLORS[step.status] || '#ddd'}`,
              background: 'var(--bg-primary, #fff)',
              cursor: 'pointer',
              fontSize: '13px',
              marginLeft: isLoop ? '16px' : '0',
            }}
          >
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <span>
                <span style={{ color: STATUS_COLORS[step.status] || '#999', marginRight: '6px' }}>
                  {STATUS_ICONS[step.status] || '?'}
                </span>
                <strong>{step.nodeType}</strong>
                <span style={{ color: '#888', marginLeft: '6px' }}>({step.nodeId})</span>
                {isLoop && (
                  <span style={{ color: '#666', marginLeft: '6px', fontSize: '11px' }}>
                    [iter {step.inputSnapshot._loopIndex}]
                  </span>
                )}
              </span>
              <span style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
                {step.retryCount > 0 && (
                  <span style={{ color: '#f0ad4e', fontSize: '11px' }} title={t('Wiederholungsanzahl')}>
                    {step.retryCount}x {t('Wiederholung')}
                  </span>
                )}
                {step.durationMs != null && (
                  <span style={{ color: '#888', fontSize: '12px' }}>{step.durationMs}ms</span>
                )}
              </span>
            </div>

            {(startStr || endStr) && (
              <div style={{ color: '#888', fontSize: '11px', marginTop: '2px' }}>
                {startStr && <span>{startStr}</span>}
                {startStr && endStr && <span> → </span>}
                {endStr && <span>{endStr}</span>}
              </div>
            )}

            {step.error && (
              <div style={{ color: '#dc3545', fontSize: '12px', marginTop: '4px' }}>{step.error}</div>
            )}
            {step.tokensUsed > 0 && (
              <div style={{ color: '#888', fontSize: '11px', marginTop: '2px' }}>
                {step.tokensUsed} {t('Tokens')}
              </div>
            )}

            <CollapsibleSection label={t('Eingabe')} content={inputStr} />
            <CollapsibleSection label={t('Ausgabe')} content={outputStr} />
          </div>
        );
      })}
    </div>
  );
};
