import { useState, useMemo, useCallback } from 'react';
import { useParams, useNavigate, useSearchParams, Link } from 'react-router';
import { Pencil, Trash2 } from 'lucide-react';
import {
  KpiStrip,
  Badge,
  StatusDot,
  DataTable,
  Tabs,
  AreaChart,
  LineChart,
  BarChart,
  RouteFlow,
  Spinner,
  MonoText,
  Sparkline,
  Toggle,
  Button,
  Modal,
  FormField,
  Input,
  Select,
  Textarea,
  Collapsible,
  ConfirmDialog,
} from '@cameleer/design-system';
import type { KpiItem, Column } from '@cameleer/design-system';
import { useGlobalFilters } from '@cameleer/design-system';
import { useRouteCatalog } from '../../api/queries/catalog';
import { useDiagramByRoute } from '../../api/queries/diagrams';
import { useProcessorMetrics } from '../../api/queries/processor-metrics';
import { useStatsTimeseries, useSearchExecutions, useExecutionStats } from '../../api/queries/executions';
import { useApplicationConfig, useUpdateApplicationConfig, useTestExpression } from '../../api/queries/commands';
import type { TapDefinition } from '../../api/queries/commands';
import type { ExecutionSummary, AppCatalogEntry, RouteSummary } from '../../api/types';
import { buildFlowSegments } from '../../utils/diagram-mapping';
import styles from './RouteDetail.module.css';

// ── Row types ────────────────────────────────────────────────────────────────

interface ExchangeRow extends ExecutionSummary {
  id: string;
}

interface ProcessorRow {
  id: string;
  processorId: string;
  callCount: number;
  avgDurationMs: number;
  p99DurationMs: number;
  errorCount: number;
  errorRate: number;
  sparkline: number[];
}

interface ErrorPattern {
  message: string;
  count: number;
  lastSeen: string;
}

// ── Processor type badge classes ─────────────────────────────────────────────

const TYPE_STYLE_MAP: Record<string, string> = {
  consumer: styles.typeConsumer,
  producer: styles.typeProducer,
  enricher: styles.typeEnricher,
  validator: styles.typeValidator,
  transformer: styles.typeTransformer,
  router: styles.typeRouter,
  processor: styles.typeProcessor,
};

function classifyProcessorType(processorId: string): string {
  const lower = processorId.toLowerCase();
  if (lower.startsWith('from(') || lower.includes('consumer')) return 'consumer';
  if (lower.startsWith('to(')) return 'producer';
  if (lower.includes('enrich')) return 'enricher';
  if (lower.includes('validate') || lower.includes('check')) return 'validator';
  if (lower.includes('unmarshal') || lower.includes('marshal')) return 'transformer';
  if (lower.includes('route') || lower.includes('choice')) return 'router';
  return 'processor';
}

// ── Processor table columns ──────────────────────────────────────────────────

function makeProcessorColumns(css: typeof styles): Column<ProcessorRow>[] {
  return [
    {
      key: 'processorId',
      header: 'Processor',
      sortable: true,
      render: (_, row) => (
        <span className={css.routeNameCell}>{row.processorId}</span>
      ),
    },
    {
      key: 'callCount',
      header: 'Invocations',
      sortable: true,
      render: (_, row) => (
        <MonoText size="sm">{row.callCount.toLocaleString()}</MonoText>
      ),
    },
    {
      key: 'avgDurationMs',
      header: 'Avg Duration',
      sortable: true,
      render: (_, row) => {
        const cls = row.avgDurationMs > 200 ? css.rateBad : row.avgDurationMs > 100 ? css.rateWarn : css.rateGood;
        return <MonoText size="sm" className={cls}>{Math.round(row.avgDurationMs)}ms</MonoText>;
      },
    },
    {
      key: 'p99DurationMs',
      header: 'p99 Duration',
      sortable: true,
      render: (_, row) => {
        const cls = row.p99DurationMs > 300 ? css.rateBad : row.p99DurationMs > 200 ? css.rateWarn : css.rateGood;
        return <MonoText size="sm" className={cls}>{Math.round(row.p99DurationMs)}ms</MonoText>;
      },
    },
    {
      key: 'errorCount',
      header: 'Errors',
      sortable: true,
      render: (_, row) => (
        <MonoText size="sm" className={row.errorCount > 10 ? css.rateBad : css.rateNeutral}>
          {row.errorCount}
        </MonoText>
      ),
    },
    {
      key: 'errorRate',
      header: 'Error Rate',
      sortable: true,
      render: (_, row) => {
        const cls = row.errorRate > 1 ? css.rateBad : row.errorRate > 0.5 ? css.rateWarn : css.rateGood;
        return <MonoText size="sm" className={cls}>{row.errorRate.toFixed(2)}%</MonoText>;
      },
    },
    {
      key: 'sparkline',
      header: 'Trend',
      render: (_, row) => (
        <Sparkline data={row.sparkline} width={80} height={24} />
      ),
    },
  ];
}

// ── Exchange table columns ───────────────────────────────────────────────────

const EXCHANGE_COLUMNS: Column<ExchangeRow>[] = [
  {
    key: 'status',
    header: 'Status',
    width: '80px',
    render: (_, row) => (
      <StatusDot variant={row.status === 'COMPLETED' ? 'success' : row.status === 'FAILED' ? 'error' : 'running'} />
    ),
  },
  {
    key: 'executionId',
    header: 'Exchange ID',
    render: (_, row) => <MonoText size="xs">{row.executionId.slice(0, 12)}</MonoText>,
  },
  {
    key: 'startTime',
    header: 'Started',
    sortable: true,
    render: (_, row) => new Date(row.startTime).toLocaleTimeString(),
  },
  {
    key: 'durationMs',
    header: 'Duration',
    sortable: true,
    render: (_, row) => `${row.durationMs}ms`,
  },
];

// ── Build KPI items ──────────────────────────────────────────────────────────

function buildDetailKpiItems(
  stats: {
    totalCount: number;
    failedCount: number;
    avgDurationMs: number;
    p99LatencyMs: number;
    activeCount: number;
    prevTotalCount: number;
    prevFailedCount: number;
    prevP99LatencyMs: number;
  } | undefined,
  throughputSparkline: number[],
  errorSparkline: number[],
  latencySparkline: number[],
): KpiItem[] {
  const totalCount = stats?.totalCount ?? 0;
  const failedCount = stats?.failedCount ?? 0;
  const prevTotalCount = stats?.prevTotalCount ?? 0;
  const p99Ms = stats?.p99LatencyMs ?? 0;
  const prevP99Ms = stats?.prevP99LatencyMs ?? 0;
  const avgMs = stats?.avgDurationMs ?? 0;
  const activeCount = stats?.activeCount ?? 0;

  const errorRate = totalCount > 0 ? (failedCount / totalCount) * 100 : 0;
  const successRate = totalCount > 0 ? ((totalCount - failedCount) / totalCount) * 100 : 100;

  const throughputPctChange = prevTotalCount > 0
    ? Math.round(((totalCount - prevTotalCount) / prevTotalCount) * 100)
    : 0;

  return [
    {
      label: 'Total Throughput',
      value: totalCount.toLocaleString(),
      trend: {
        label: throughputPctChange >= 0 ? `\u25B2 +${throughputPctChange}%` : `\u25BC ${throughputPctChange}%`,
        variant: throughputPctChange >= 0 ? 'success' as const : 'error' as const,
      },
      subtitle: `${activeCount} in-flight`,
      sparkline: throughputSparkline,
      borderColor: 'var(--amber)',
    },
    {
      label: 'System Error Rate',
      value: `${errorRate.toFixed(2)}%`,
      trend: {
        label: errorRate < 1 ? '\u25BC low' : `\u25B2 ${errorRate.toFixed(1)}%`,
        variant: errorRate < 1 ? 'success' as const : 'error' as const,
      },
      subtitle: `${failedCount} errors / ${totalCount.toLocaleString()} total`,
      sparkline: errorSparkline,
      borderColor: errorRate < 1 ? 'var(--success)' : 'var(--error)',
    },
    {
      label: 'Latency P99',
      value: `${p99Ms}ms`,
      trend: {
        label: p99Ms > prevP99Ms ? `\u25B2 +${p99Ms - prevP99Ms}ms` : `\u25BC ${prevP99Ms - p99Ms}ms`,
        variant: p99Ms > 300 ? 'error' as const : 'warning' as const,
      },
      subtitle: `Avg ${avgMs}ms \u00B7 SLA <300ms`,
      sparkline: latencySparkline,
      borderColor: p99Ms > 300 ? 'var(--warning)' : 'var(--success)',
    },
    {
      label: 'Success Rate',
      value: `${successRate.toFixed(1)}%`,
      trend: { label: '\u2194', variant: 'muted' as const },
      subtitle: `${totalCount - failedCount} ok / ${failedCount} failed`,
      borderColor: 'var(--success)',
    },
    {
      label: 'In-Flight',
      value: String(activeCount),
      trend: { label: '\u2194', variant: 'muted' as const },
      subtitle: `${activeCount} active exchanges`,
      borderColor: 'var(--amber)',
    },
  ];
}

// ── Component ────────────────────────────────────────────────────────────────

export default function RouteDetail() {
  const { appId, routeId } = useParams();
  const navigate = useNavigate();
  const { timeRange } = useGlobalFilters();
  const timeFrom = timeRange.start.toISOString();
  const timeTo = timeRange.end.toISOString();

  const [searchParams] = useSearchParams();
  const [activeTab, setActiveTab] = useState(searchParams.get('tab') || 'performance');
  const [recentSortField, setRecentSortField] = useState<string>('startTime');
  const [recentSortDir, setRecentSortDir] = useState<'asc' | 'desc'>('desc');

  // ── Tap modal state ────────────────────────────────────────────────────────
  const [tapModalOpen, setTapModalOpen] = useState(false);
  const [editingTap, setEditingTap] = useState<TapDefinition | null>(null);
  const [tapName, setTapName] = useState('');
  const [tapProcessor, setTapProcessor] = useState('');
  const [tapLanguage, setTapLanguage] = useState('simple');
  const [tapTarget, setTapTarget] = useState<'INPUT' | 'OUTPUT' | 'BOTH'>('OUTPUT');
  const [tapExpression, setTapExpression] = useState('');
  const [tapType, setTapType] = useState<'BUSINESS_OBJECT' | 'CORRELATION' | 'EVENT' | 'CUSTOM'>('BUSINESS_OBJECT');
  const [tapEnabled, setTapEnabled] = useState(true);
  const [deletingTap, setDeletingTap] = useState<TapDefinition | null>(null);

  // ── Test expression state ──────────────────────────────────────────────────
  const [testTab, setTestTab] = useState('recent');
  const [testPayload, setTestPayload] = useState('');
  const [testResult, setTestResult] = useState<{ result?: string; error?: string } | null>(null);
  const [testExchangeId, setTestExchangeId] = useState('');

  const handleRecentSortChange = useCallback((key: string, dir: 'asc' | 'desc') => {
    setRecentSortField(key);
    setRecentSortDir(dir);
  }, []);

  // ── API queries ────────────────────────────────────────────────────────────
  const { data: catalog } = useRouteCatalog();
  const { data: diagram } = useDiagramByRoute(appId, routeId);
  const { data: processorMetrics, isLoading: processorLoading } = useProcessorMetrics(routeId ?? null, appId);
  const { data: stats } = useExecutionStats(timeFrom, timeTo, routeId, appId);
  const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, routeId, appId);
  const { data: recentResult, isLoading: recentLoading } = useSearchExecutions({
    timeFrom,
    timeTo,
    routeId: routeId || undefined,
    applicationId: appId || undefined,
    sortField: recentSortField,
    sortDir: recentSortDir,
    offset: 0,
    limit: 50,
  });
  const { data: errorResult } = useSearchExecutions({
    timeFrom,
    timeTo,
    routeId: routeId || undefined,
    applicationId: appId || undefined,
    status: 'FAILED',
    offset: 0,
    limit: 200,
  });

  // ── Application config ──────────────────────────────────────────────────────
  const config = useApplicationConfig(appId);
  const updateConfig = useUpdateApplicationConfig();
  const testExpressionMutation = useTestExpression();

  const isRecording = config.data?.routeRecording?.[routeId!] !== false;

  function toggleRecording() {
    if (!config.data) return;
    const routeRecording = { ...config.data.routeRecording, [routeId!]: !isRecording };
    updateConfig.mutate({ ...config.data, routeRecording });
  }

  // ── Derived data ───────────────────────────────────────────────────────────

  const appEntry: AppCatalogEntry | undefined = useMemo(() =>
    (catalog || []).find((e: AppCatalogEntry) => e.appId === appId),
    [catalog, appId],
  );

  const routeSummary: RouteSummary | undefined = useMemo(() =>
    appEntry?.routes?.find((r: RouteSummary) => r.routeId === routeId),
    [appEntry, routeId],
  );

  const health = appEntry?.health ?? 'unknown';
  const exchangeCount = routeSummary?.exchangeCount ?? 0;
  const lastSeen = routeSummary?.lastSeen
    ? new Date(routeSummary.lastSeen).toLocaleString()
    : '\u2014';

  const healthVariant = useMemo((): 'success' | 'warning' | 'error' | 'dead' => {
    const h = health.toLowerCase();
    if (h === 'healthy') return 'success';
    if (h === 'degraded') return 'warning';
    if (h === 'unhealthy') return 'error';
    return 'dead';
  }, [health]);

  // Route flow from diagram
  const diagramFlows = useMemo(() => {
    if (!diagram?.nodes) return [];
    return buildFlowSegments(diagram.nodes, []).flows;
  }, [diagram]);

  // Processor table rows
  const processorRows: ProcessorRow[] = useMemo(() =>
    (processorMetrics || []).map((p: any) => {
      const callCount = p.callCount ?? 0;
      const errorCount = p.errorCount ?? 0;
      const errRate = callCount > 0 ? (errorCount / callCount) * 100 : 0;
      return {
        id: p.processorId,
        processorId: p.processorId,
        type: classifyProcessorType(p.processorId ?? ''),
        callCount,
        avgDurationMs: p.avgDurationMs ?? 0,
        p99DurationMs: p.p99DurationMs ?? 0,
        errorCount,
        errorRate: Number(errRate.toFixed(2)),
        sparkline: p.sparkline ?? [],
      };
    }),
    [processorMetrics],
  );

  // Timeseries-derived data
  const throughputSparkline = useMemo(() =>
    (timeseries?.buckets || []).map((b) => b.totalCount),
    [timeseries],
  );
  const errorSparkline = useMemo(() =>
    (timeseries?.buckets || []).map((b) => b.failedCount),
    [timeseries],
  );
  const latencySparkline = useMemo(() =>
    (timeseries?.buckets || []).map((b) => b.p99DurationMs),
    [timeseries],
  );

  const chartData = useMemo(() =>
    (timeseries?.buckets || []).map((b) => {
      const ts = new Date(b.time);
      return {
        time: !isNaN(ts.getTime())
          ? ts.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
          : '\u2014',
        throughput: b.totalCount,
        latency: b.avgDurationMs,
        errors: b.failedCount,
        successRate: b.totalCount > 0 ? ((b.totalCount - b.failedCount) / b.totalCount) * 100 : 100,
      };
    }),
    [timeseries],
  );

  // Exchange rows
  const exchangeRows: ExchangeRow[] = useMemo(() =>
    (recentResult?.data || []).map((e: ExecutionSummary) => ({ ...e, id: e.executionId })),
    [recentResult],
  );

  // Error patterns
  const errorPatterns: ErrorPattern[] = useMemo(() => {
    const failed = (errorResult?.data || []) as ExecutionSummary[];
    const grouped = new Map<string, { count: number; lastSeen: string }>();
    for (const ex of failed) {
      const msg = ex.errorMessage || 'Unknown error';
      const existing = grouped.get(msg);
      if (!existing) {
        grouped.set(msg, { count: 1, lastSeen: ex.startTime ?? '' });
      } else {
        existing.count += 1;
        if ((ex.startTime ?? '') > existing.lastSeen) {
          existing.lastSeen = ex.startTime ?? '';
        }
      }
    }
    return Array.from(grouped.entries())
      .map(([message, { count, lastSeen: ls }]) => ({
        message,
        count,
        lastSeen: ls ? new Date(ls).toLocaleString() : '\u2014',
      }))
      .sort((a, b) => b.count - a.count);
  }, [errorResult]);

  // Route taps — cross-reference config taps with diagram processor IDs
  const routeTaps = useMemo(() => {
    if (!config.data?.taps || !diagram) return [];
    const routeProcessorIds = new Set(
      (diagram.nodes || []).map((n: any) => n.id).filter(Boolean),
    );
    return config.data.taps.filter(t => routeProcessorIds.has(t.processorId));
  }, [config.data?.taps, diagram]);

  const activeTapCount = routeTaps.filter(t => t.enabled).length;

  // KPI items
  const kpiItems = useMemo(() => {
    const base = buildDetailKpiItems(stats, throughputSparkline, errorSparkline, latencySparkline);
    base.push({
      label: 'Active Taps',
      value: String(activeTapCount),
      trend: { label: `${routeTaps.length} total`, variant: 'muted' as const },
      subtitle: `${activeTapCount} enabled / ${routeTaps.length} configured`,
      borderColor: 'var(--running)',
    });
    return base;
  }, [stats, throughputSparkline, errorSparkline, latencySparkline, activeTapCount, routeTaps.length]);

  const processorColumns = useMemo(() => makeProcessorColumns(styles), []);

  const tabs = [
    { label: 'Performance', value: 'performance' },
    { label: 'Recent Executions', value: 'executions', count: exchangeRows.length },
    { label: 'Error Patterns', value: 'errors', count: errorPatterns.length },
    { label: 'Taps', value: 'taps', count: routeTaps.length },
  ];

  // ── Tap helpers ──────────────────────────────────────────────────────────

  const processorOptions = useMemo(() => {
    if (!diagram?.nodes) return [];
    return (diagram.nodes as Array<{ id?: string; label?: string }>)
      .filter((n) => n.id)
      .map((n) => ({ value: n.id!, label: n.label || n.id! }));
  }, [diagram]);

  function openTapModal(tap: TapDefinition | null) {
    if (tap) {
      setEditingTap(tap);
      setTapName(tap.attributeName);
      setTapProcessor(tap.processorId);
      setTapLanguage(tap.language);
      setTapTarget(tap.target);
      setTapExpression(tap.expression);
      setTapType(tap.attributeType);
      setTapEnabled(tap.enabled);
    } else {
      setEditingTap(null);
      setTapName('');
      setTapProcessor(processorOptions[0]?.value ?? '');
      setTapLanguage('simple');
      setTapTarget('OUTPUT');
      setTapExpression('');
      setTapType('BUSINESS_OBJECT');
      setTapEnabled(true);
    }
    setTestResult(null);
    setTestPayload('');
    setTestExchangeId('');
    setTapModalOpen(true);
  }

  function saveTap() {
    if (!config.data) return;
    const tap: TapDefinition = {
      tapId: editingTap?.tapId || `tap-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
      processorId: tapProcessor,
      target: tapTarget,
      expression: tapExpression,
      language: tapLanguage,
      attributeName: tapName,
      attributeType: tapType,
      enabled: tapEnabled,
      version: editingTap ? editingTap.version + 1 : 1,
    };
    const taps = editingTap
      ? config.data.taps.map(t => t.tapId === editingTap.tapId ? tap : t)
      : [...(config.data.taps || []), tap];
    updateConfig.mutate({ ...config.data, taps });
    setTapModalOpen(false);
  }

  function deleteTap(tap: TapDefinition) {
    if (!config.data) return;
    const taps = config.data.taps.filter(t => t.tapId !== tap.tapId);
    updateConfig.mutate({ ...config.data, taps });
    setDeletingTap(null);
  }

  function toggleTapEnabled(tap: TapDefinition) {
    if (!config.data) return;
    const taps = config.data.taps.map(t =>
      t.tapId === tap.tapId ? { ...t, enabled: !t.enabled } : t,
    );
    updateConfig.mutate({ ...config.data, taps });
  }

  function runTestExpression() {
    if (!appId) return;
    const body = testTab === 'recent' ? testExchangeId : testPayload;
    testExpressionMutation.mutate(
      { application: appId, expression: tapExpression, language: tapLanguage, body, target: tapTarget },
      { onSuccess: (data) => setTestResult(data), onError: (err) => setTestResult({ error: (err as Error).message }) },
    );
  }

  const tapColumns: Column<TapDefinition & { id: string }>[] = useMemo(() => [
    {
      key: 'attributeName',
      header: 'Attribute',
      sortable: true,
      render: (_, row) => <span>{row.attributeName}</span>,
    },
    {
      key: 'processorId',
      header: 'Processor',
      sortable: true,
      render: (_, row) => <MonoText size="xs">{row.processorId}</MonoText>,
    },
    {
      key: 'expression',
      header: 'Expression',
      render: (_, row) => <MonoText size="xs">{row.expression}</MonoText>,
    },
    {
      key: 'language',
      header: 'Language',
      render: (_, row) => <Badge label={row.language} color="auto" />,
    },
    {
      key: 'target',
      header: 'Target',
      render: (_, row) => <Badge label={row.target} color="auto" />,
    },
    {
      key: 'attributeType',
      header: 'Type',
      render: (_, row) => <Badge label={row.attributeType} color="auto" />,
    },
    {
      key: 'enabled',
      header: 'Enabled',
      width: '80px',
      render: (_, row) => (
        <Toggle
          checked={row.enabled}
          onChange={() => toggleTapEnabled(row)}
        />
      ),
    },
    {
      key: 'actions' as any,
      header: '',
      width: '80px',
      render: (_, row) => (
        <div className={styles.tapActions}>
          <button className={styles.tapActionBtn} title="Edit" onClick={() => openTapModal(row)}><Pencil size={14} /></button>
          <button className={styles.tapActionBtn} title="Delete" onClick={() => setDeletingTap(row)}><Trash2 size={14} /></button>
        </div>
      ),
    },
  ], [config.data, processorOptions]);

  const languageOptions = [
    { value: 'simple', label: 'Simple' },
    { value: 'jsonpath', label: 'JSONPath' },
    { value: 'xpath', label: 'XPath' },
    { value: 'jq', label: 'jq' },
    { value: 'groovy', label: 'Groovy' },
  ];

  const targetOptions = [
    { value: 'INPUT', label: 'Input' },
    { value: 'OUTPUT', label: 'Output' },
    { value: 'BOTH', label: 'Both' },
  ];

  const typeChoices: Array<{ value: TapDefinition['attributeType']; label: string; tooltip: string }> = [
    { value: 'BUSINESS_OBJECT', label: 'Business Object', tooltip: 'A key business identifier like orderId, customerId, or invoiceNumber' },
    { value: 'CORRELATION', label: 'Correlation', tooltip: 'Used to correlate related exchanges across routes or services' },
    { value: 'EVENT', label: 'Event', tooltip: 'Marks a business event occurrence like orderPlaced or paymentReceived' },
    { value: 'CUSTOM', label: 'Custom', tooltip: 'General-purpose attribute for any other extraction need' },
  ];

  const recentExchangeOptions = useMemo(() =>
    exchangeRows.slice(0, 20).map(e => ({
      value: e.executionId,
      label: `${e.executionId.slice(0, 12)} — ${e.status}`,
    })),
    [exchangeRows],
  );

  // ── Render ─────────────────────────────────────────────────────────────────

  return (
    <div>
      <Link to={`/routes/${appId}`} className={styles.backLink}>
        &larr; {appId} routes
      </Link>

      {/* Route header card */}
      <div className={styles.headerCard}>
        <div className={styles.headerRow}>
          <div className={styles.headerLeft}>
            <StatusDot variant={healthVariant} />
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700 }}>{routeId}</h2>
            <Badge label={appId ?? ''} color="auto" />
          </div>
          <div className={styles.headerRight}>
            <div className={styles.recordingPill}>
              <span className={styles.recordingLabel}>Recording</span>
              <Toggle checked={isRecording} onChange={toggleRecording} />
            </div>
            <div className={styles.headerStat}>
              <div className={styles.headerStatLabel}>Exchanges</div>
              <div className={styles.headerStatValue}>{exchangeCount.toLocaleString()}</div>
            </div>
            <div className={styles.headerStat}>
              <div className={styles.headerStatLabel}>Last Seen</div>
              <div className={styles.headerStatValue}>{lastSeen}</div>
            </div>
          </div>
        </div>
      </div>

      {/* KPI strip */}
      <KpiStrip items={kpiItems} />

      {/* Diagram + Processor Stats grid */}
      <div className={styles.diagramStatsGrid}>
        <div className={styles.diagramPane}>
          <div className={styles.paneTitle}>Route Diagram</div>
          {diagramFlows.length > 0 ? (
            <RouteFlow flows={diagramFlows} />
          ) : (
            <div className={styles.emptyText}>
              No diagram available for this route.
            </div>
          )}
        </div>
        <div className={styles.statsPane}>
          <div className={styles.paneTitle}>Processor Stats</div>
          {processorLoading ? (
            <Spinner size="sm" />
          ) : processorRows.length > 0 ? (
            <DataTable columns={processorColumns} data={processorRows} sortable pageSize={10} />
          ) : (
            <div className={styles.emptyText}>
              No processor data available.
            </div>
          )}
        </div>
      </div>

      {/* Processor Performance table (full width) */}
      <div className={styles.tableSection}>
        <div className={styles.tableHeader}>
          <span className={styles.tableTitle}>Processor Performance</span>
          <div className={styles.tableRight}>
            <span className={styles.tableMeta}>{processorRows.length} processors</span>
            <Badge label="LIVE" color="success" />
          </div>
        </div>
        <DataTable
          columns={processorColumns}
          data={processorRows}
          sortable
        />
      </div>

      {/* Route Flow section */}
      {diagramFlows.length > 0 && (
        <div className={styles.routeFlowSection}>
          <div className={styles.tableHeader}>
            <span className={styles.tableTitle}>Route Flow</span>
          </div>
          <RouteFlow flows={diagramFlows} />
        </div>
      )}

      {/* Tabbed section: Performance charts, Recent Executions, Error Patterns */}
      <div className={styles.tabSection}>
        <Tabs tabs={tabs} active={activeTab} onChange={setActiveTab} />

        {activeTab === 'performance' && (
          <div className={styles.chartGrid} style={{ marginTop: 16 }}>
            <div className={styles.chartCard}>
              <div className={styles.chartTitle}>Throughput</div>
              <AreaChart
                series={[{
                  label: 'Throughput',
                  data: chartData.map((d, i) => ({ x: i, y: d.throughput })),
                }]}
                height={200}
              />
            </div>
            <div className={styles.chartCard}>
              <div className={styles.chartTitle}>Latency</div>
              <LineChart
                series={[{
                  label: 'Latency',
                  data: chartData.map((d, i) => ({ x: i, y: d.latency })),
                }]}
                height={200}
                threshold={{ value: 300, label: 'SLA 300ms' }}
              />
            </div>
            <div className={styles.chartCard}>
              <div className={styles.chartTitle}>Errors</div>
              <BarChart
                series={[{
                  label: 'Errors',
                  data: chartData.map((d) => ({ x: d.time, y: d.errors })),
                }]}
                height={200}
              />
            </div>
            <div className={styles.chartCard}>
              <div className={styles.chartTitle}>Success Rate</div>
              <AreaChart
                series={[{
                  label: 'Success Rate',
                  data: chartData.map((d, i) => ({ x: i, y: d.successRate })),
                }]}
                height={200}
              />
            </div>
          </div>
        )}

        {activeTab === 'executions' && (
          <div className={styles.executionsTable} style={{ marginTop: 16 }}>
            {recentLoading ? (
              <div style={{ padding: 24, display: 'flex', justifyContent: 'center' }}>
                <Spinner size="sm" />
              </div>
            ) : (
              <DataTable
                columns={EXCHANGE_COLUMNS}
                data={exchangeRows}
                onRowClick={(row) => navigate(`/exchanges/${row.executionId}`)}
                sortable
                pageSize={20}
                onSortChange={handleRecentSortChange}
              />
            )}
          </div>
        )}

        {activeTab === 'errors' && (
          <div className={styles.errorPatterns} style={{ marginTop: 16 }}>
            {errorPatterns.length === 0 ? (
              <div className={styles.emptyText}>
                No error patterns found in the selected time range.
              </div>
            ) : (
              errorPatterns.map((ep, i) => (
                <div key={i} className={styles.errorRow}>
                  <span className={styles.errorMessage} title={ep.message}>{ep.message}</span>
                  <span className={styles.errorCount}>{ep.count}x</span>
                  <span className={styles.errorTime}>{ep.lastSeen}</span>
                </div>
              ))
            )}
          </div>
        )}

        {activeTab === 'taps' && (
          <div className={styles.tapsSection}>
            <div className={styles.tapsHeader}>
              <span className={styles.tapsTitle}>Data Extraction Taps</span>
              <Button variant="primary" size="sm" onClick={() => openTapModal(null)}>+ Add Tap</Button>
            </div>
            {routeTaps.length === 0 ? (
              <div className={styles.emptyState}>
                No taps configured for this route. Add a tap to extract business attributes from exchange data.
              </div>
            ) : (
              <DataTable
                columns={tapColumns}
                data={routeTaps.map(t => ({ ...t, id: t.tapId }))}
                flush
              />
            )}
          </div>
        )}
      </div>

      {/* Tap Modal */}
      <Modal open={tapModalOpen} onClose={() => setTapModalOpen(false)} title={editingTap ? 'Edit Tap' : 'Add Tap'} size="lg">
        <div className={styles.tapModalBody}>
          <FormField label="Attribute Name">
            <Input value={tapName} onChange={(e) => setTapName(e.target.value)} placeholder="e.g. orderId" />
          </FormField>

          <FormField label="Processor">
            <Select
              options={processorOptions}
              value={tapProcessor}
              onChange={(e) => setTapProcessor(e.target.value)}
            />
          </FormField>

          <div className={styles.tapFormRow}>
            <FormField label="Language">
              <Select
                options={languageOptions}
                value={tapLanguage}
                onChange={(e) => setTapLanguage(e.target.value)}
              />
            </FormField>
            <FormField label="Target">
              <Select
                options={targetOptions}
                value={tapTarget}
                onChange={(e) => setTapTarget(e.target.value as 'INPUT' | 'OUTPUT' | 'BOTH')}
              />
            </FormField>
          </div>

          <FormField label="Expression">
            <Textarea
              className={styles.monoTextarea}
              value={tapExpression}
              onChange={(e) => setTapExpression(e.target.value)}
              placeholder="e.g. ${body.orderId}"
              rows={3}
            />
          </FormField>

          <FormField label="Type">
            <div className={styles.typeSelector}>
              {typeChoices.map(tc => (
                <button
                  key={tc.value}
                  type="button"
                  title={tc.tooltip}
                  className={`${styles.typeOption} ${tapType === tc.value ? styles.typeOptionActive : ''}`}
                  onClick={() => setTapType(tc.value)}
                >
                  {tc.label}
                </button>
              ))}
            </div>
          </FormField>

          <div className={styles.tapFormRow}>
            <FormField label="Enabled">
              <Toggle checked={tapEnabled} onChange={() => setTapEnabled(!tapEnabled)} />
            </FormField>
          </div>

          {/* Test Expression */}
          <Collapsible title="Test Expression" defaultOpen>
            <div className={styles.testSection}>
              <div className={styles.testTabs}>
                <button
                  type="button"
                  className={`${styles.testTabBtn} ${testTab === 'recent' ? styles.testTabBtnActive : ''}`}
                  onClick={() => setTestTab('recent')}
                >
                  Recent Exchange
                </button>
                <button
                  type="button"
                  className={`${styles.testTabBtn} ${testTab === 'custom' ? styles.testTabBtnActive : ''}`}
                  onClick={() => setTestTab('custom')}
                >
                  Custom Payload
                </button>
              </div>

              {testTab === 'recent' && (
                <div className={styles.testBody}>
                  <Select
                    options={recentExchangeOptions.length > 0 ? recentExchangeOptions : [{ value: '', label: 'No recent exchanges' }]}
                    value={testExchangeId}
                    onChange={(e) => setTestExchangeId(e.target.value)}
                  />
                </div>
              )}

              {testTab === 'custom' && (
                <div className={styles.testBody}>
                  <Textarea
                    className={styles.monoTextarea}
                    value={testPayload}
                    onChange={(e) => setTestPayload(e.target.value)}
                    placeholder='{"orderId": "12345", ...}'
                    rows={4}
                  />
                </div>
              )}

              <div className={styles.testBody}>
                <Button
                  variant="secondary"
                  size="sm"
                  onClick={runTestExpression}
                  loading={testExpressionMutation.isPending}
                  disabled={!tapExpression}
                >
                  Test
                </Button>
              </div>

              {testResult && (
                <div className={`${styles.testResult} ${testResult.error ? styles.testError : styles.testSuccess}`}>
                  {testResult.error ?? testResult.result ?? 'No result'}
                </div>
              )}
            </div>
          </Collapsible>

          <div className={styles.tapModalFooter}>
            <Button variant="secondary" onClick={() => setTapModalOpen(false)}>Cancel</Button>
            <Button variant="primary" onClick={saveTap} disabled={!tapName || !tapProcessor || !tapExpression}>Save</Button>
          </div>
        </div>
      </Modal>

      {/* Delete Tap Confirm */}
      <ConfirmDialog
        open={!!deletingTap}
        onClose={() => setDeletingTap(null)}
        onConfirm={() => deletingTap && deleteTap(deletingTap)}
        title="Delete Tap"
        message={`This will remove the tap "${deletingTap?.attributeName ?? ''}" from the configuration.`}
        confirmText={deletingTap?.attributeName ?? ''}
        confirmLabel="Delete"
        variant="danger"
      />
    </div>
  );
}
