import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router';
import { ExternalLink, RefreshCw, Pencil, LayoutGrid, List, ChevronRight, ChevronDown } from 'lucide-react';
import {
  StatCard, StatusDot, Badge, MonoText,
  GroupCard, DataTable, EventFeed,
  LogViewer, ButtonGroup, SectionHeader, Toggle, Select, Button, useToast,
  Alert, ConfirmDialog,
} from '@cameleer/design-system';
import type { Column, FeedEvent, LogEntry, ButtonGroupItem } from '@cameleer/design-system';
import styles from './AgentHealth.module.css';
import sectionStyles from '../../styles/section-card.module.css';
import logStyles from '../../styles/log-panel.module.css';
import { useAgents, useAgentEvents } from '../../api/queries/agents';
import { useApplicationLogs } from '../../api/queries/logs';
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
import { useCatalog, useDismissApp } from '../../api/queries/catalog';
import { useIsAdmin } from '../../auth/auth-store';
import { useEnvironmentStore } from '../../api/environment-store';
import type { ConfigUpdateResponse } from '../../api/queries/commands';
import type { AgentInstance } from '../../api/types';
import { timeAgo } from '../../utils/format-utils';
import { formatUptime, mapLogLevel, eventSeverity, eventIcon } from '../../utils/agent-utils';

// ── Helpers ──────────────────────────────────────────────────────────────────

function formatErrorRate(rate?: number): string {
  if (rate == null) return '\u2014';
  return `${(rate * 100).toFixed(1)}%`;
}

type NormStatus = 'live' | 'stale' | 'dead';

function normalizeStatus(status: string): NormStatus {
  return status.toLowerCase() as NormStatus;
}

function statusColor(s: NormStatus): 'success' | 'warning' | 'error' {
  if (s === 'live') return 'success';
  if (s === 'stale') return 'warning';
  return 'error';
}

// ── Data grouping ────────────────────────────────────────────────────────────

interface AppGroup {
  appId: string;
  instances: AgentInstance[];
  liveCount: number;
  staleCount: number;
  deadCount: number;
  totalTps: number;
  totalActiveRoutes: number;
  totalRoutes: number;
}

function groupByApp(agentList: AgentInstance[]): AppGroup[] {
  const map = new Map<string, AgentInstance[]>();
  for (const a of agentList) {
    const app = a.applicationId;
    const list = map.get(app) ?? [];
    list.push(a);
    map.set(app, list);
  }
  return Array.from(map.entries()).map(([appId, instances]) => ({
    appId,
    instances,
    liveCount: instances.filter((i) => normalizeStatus(i.status) === 'live').length,
    staleCount: instances.filter((i) => normalizeStatus(i.status) === 'stale').length,
    deadCount: instances.filter((i) => normalizeStatus(i.status) === 'dead').length,
    totalTps: instances.reduce((s, i) => s + (i.tps ?? 0), 0),
    totalActiveRoutes: instances.reduce((s, i) => s + (i.activeRoutes ?? 0), 0),
    totalRoutes: instances.reduce((s, i) => s + (i.totalRoutes ?? 0), 0),
  }));
}

function appHealth(group: AppGroup): 'success' | 'warning' | 'error' {
  if (group.deadCount > 0) return 'error';
  if (group.staleCount > 0) return 'warning';
  return 'success';
}

function latestHeartbeat(group: AppGroup): string | undefined {
  let latest: string | undefined;
  for (const inst of group.instances) {
    if (inst.lastHeartbeat && (!latest || inst.lastHeartbeat > latest)) {
      latest = inst.lastHeartbeat;
    }
  }
  return latest;
}

// ── Detail sub-components ────────────────────────────────────────────────────

const LOG_LEVEL_ITEMS: ButtonGroupItem[] = [
  { value: 'error', label: 'Error', color: 'var(--error)' },
  { value: 'warn', label: 'Warn', color: 'var(--warning)' },
  { value: 'info', label: 'Info', color: 'var(--success)' },
  { value: 'debug', label: 'Debug', color: 'var(--running)' },
  { value: 'trace', label: 'Trace', color: 'var(--text-muted)' },
];

const LOG_SOURCE_ITEMS: ButtonGroupItem[] = [
  { value: 'app', label: 'App' },
  { value: 'agent', label: 'Agent' },
  { value: 'container', label: 'Container' },
];

function CompactAppCard({ group, onExpand, onNavigate }: { group: AppGroup; onExpand: () => void; onNavigate: () => void }) {
  const health = appHealth(group);
  const heartbeat = latestHeartbeat(group);
  const isHealthy = health === 'success';

  const variantClass =
    health === 'success' ? styles.compactCardSuccess
    : health === 'warning' ? styles.compactCardWarning
    : styles.compactCardError;

  return (
    <div
      className={`${styles.compactCard} ${variantClass}`}
      onClick={onExpand}
      role="button"
      tabIndex={0}
      onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') onExpand(); }}
    >
      <div className={styles.compactCardHeader}>
        <span
          className={styles.compactCardName}
          onClick={(e) => { e.stopPropagation(); onNavigate(); }}
          role="link"
        >
          {group.appId}
        </span>
        <ChevronRight size={14} className={styles.compactCardChevron} />
      </div>
      <div className={styles.compactCardMeta}>
        <span className={styles.compactCardLive}>
          {group.liveCount}/{group.instances.length} live
        </span>
        <span className={styles.compactCardTps}>
          {group.totalTps.toFixed(1)}/s
        </span>
        <span className={isHealthy ? styles.compactCardHeartbeat : styles.compactCardHeartbeatWarn}>
          {heartbeat ? timeAgo(heartbeat) : '\u2014'}
        </span>
      </div>
    </div>
  );
}

// ── AgentHealth page ─────────────────────────────────────────────────────────

export default function AgentHealth() {
  const { appId } = useParams();
  const navigate = useNavigate();
  const { toast } = useToast();
  const selectedEnv = useEnvironmentStore((s) => s.environment);
  const { data: agents } = useAgents(undefined, appId, selectedEnv);
  const { data: appConfig } = useApplicationConfig(appId);
  const updateConfig = useUpdateApplicationConfig();

  const isAdmin = useIsAdmin();
  const selectedEnvForCatalog = useEnvironmentStore((s) => s.environment);
  const { data: catalogApps } = useCatalog(selectedEnvForCatalog);
  const dismissApp = useDismissApp();
  const catalogEntry = catalogApps?.find((a) => a.slug === appId);

  const [confirmDismissOpen, setConfirmDismissOpen] = useState(false);
  const [viewMode, setViewMode] = useState<'compact' | 'expanded'>(() => {
    const saved = localStorage.getItem('cameleer:runtime:viewMode');
    return saved === 'expanded' ? 'expanded' : 'compact';
  });
  const [expandedApps, setExpandedApps] = useState<Set<string>>(new Set());

  const toggleViewMode = useCallback((mode: 'compact' | 'expanded') => {
    setViewMode(mode);
    setExpandedApps(new Set());
    localStorage.setItem('cameleer:runtime:viewMode', mode);
  }, []);

  const toggleAppExpanded = useCallback((appId: string) => {
    setExpandedApps((prev) => {
      const next = new Set(prev);
      if (next.has(appId)) next.delete(appId);
      else next.add(appId);
      return next;
    });
  }, []);

  const [animatingApps, setAnimatingApps] = useState<Map<string, 'expanding' | 'collapsing'>>(new Map());
  const animationTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());

  const animateToggle = useCallback((appIdToToggle: string) => {
    // Clear any existing timer for this app
    const existing = animationTimers.current.get(appIdToToggle);
    if (existing) clearTimeout(existing);

    const isCurrentlyExpanded = expandedApps.has(appIdToToggle);

    if (isCurrentlyExpanded) {
      // Collapsing: start animation, then remove from expandedApps after transition
      setAnimatingApps((prev) => new Map(prev).set(appIdToToggle, 'collapsing'));
      const timer = setTimeout(() => {
        setExpandedApps((prev) => {
          const next = new Set(prev);
          next.delete(appIdToToggle);
          return next;
        });
        setAnimatingApps((prev) => {
          const next = new Map(prev);
          next.delete(appIdToToggle);
          return next;
        });
        animationTimers.current.delete(appIdToToggle);
      }, 200);
      animationTimers.current.set(appIdToToggle, timer);
    } else {
      // Expanding: add to expandedApps immediately, animate in
      setExpandedApps((prev) => new Set(prev).add(appIdToToggle));
      setAnimatingApps((prev) => new Map(prev).set(appIdToToggle, 'expanding'));
      // Use requestAnimationFrame to ensure the collapsed state renders first
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          setAnimatingApps((prev) => {
            const next = new Map(prev);
            next.delete(appIdToToggle);
            return next;
          });
        });
      });
    }
  }, [expandedApps]);

  // Cleanup timers on unmount
  useEffect(() => {
    return () => {
      animationTimers.current.forEach((timer) => clearTimeout(timer));
    };
  }, []);

  const [configEditing, setConfigEditing] = useState(false);
  const [configDraft, setConfigDraft] = useState<Record<string, string | boolean>>({});

  const startConfigEdit = useCallback(() => {
    if (!appConfig) return;
    setConfigDraft({
      applicationLogLevel: appConfig.applicationLogLevel ?? 'INFO',
      agentLogLevel: appConfig.agentLogLevel ?? 'INFO',
      engineLevel: appConfig.engineLevel ?? 'REGULAR',
      payloadCaptureMode: appConfig.payloadCaptureMode ?? 'BOTH',
      metricsEnabled: appConfig.metricsEnabled,
    });
    setConfigEditing(true);
  }, [appConfig]);

  const saveConfigEdit = useCallback(() => {
    if (!appConfig) return;
    const updated = { ...appConfig, ...configDraft };
    updateConfig.mutate({ config: updated, environment: selectedEnv }, {
      onSuccess: (saved: ConfigUpdateResponse) => {
        setConfigEditing(false);
        setConfigDraft({});
        if (saved.pushResult.success) {
          toast({ title: 'Config updated', description: `${appId} (v${saved.config.version}) — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents`, variant: 'success' });
        } else {
          const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
          toast({ title: 'Config updated — partial push failure', description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
        }
      },
      onError: () => {
        toast({ title: 'Config update failed', variant: 'error', duration: 86_400_000 });
      },
    });
  }, [appConfig, configDraft, updateConfig, toast, appId]);
  const [eventSortAsc, setEventSortAsc] = useState(false);
  const [eventRefreshTo, setEventRefreshTo] = useState<string | undefined>();
  const { data: events } = useAgentEvents(appId, undefined, 50, eventRefreshTo, selectedEnv);

  const [logSearch, setLogSearch] = useState('');
  const [logLevels, setLogLevels] = useState<Set<string>>(new Set());
  const [logSource, setLogSource] = useState<string>('');  // '' = all, 'app', 'agent'
  const [logSortAsc, setLogSortAsc] = useState(false);
  const [logRefreshTo, setLogRefreshTo] = useState<string | undefined>();
  const { data: rawLogs } = useApplicationLogs(appId, undefined, { toOverride: logRefreshTo, source: logSource || undefined });
  const logEntries = useMemo<LogEntry[]>(() => {
    const mapped = (rawLogs || []).map((l) => ({
      timestamp: l.timestamp ?? '',
      level: mapLogLevel(l.level),
      message: l.message ?? '',
    }));
    return logSortAsc ? mapped.toReversed() : mapped;
  }, [rawLogs, logSortAsc]);
  const logSearchLower = logSearch.toLowerCase();
  const filteredLogs = logEntries
    .filter((l) => logLevels.size === 0 || logLevels.has(l.level))
    .filter((l) => !logSearchLower || l.message.toLowerCase().includes(logSearchLower));

  const agentList = agents ?? [];

  const groups = useMemo(() => groupByApp(agentList).sort((a, b) => a.appId.localeCompare(b.appId)), [agentList]);

  // Aggregate stats
  const totalInstances = agentList.length;
  const liveCount = agentList.filter((a) => normalizeStatus(a.status) === 'live').length;
  const staleCount = agentList.filter((a) => normalizeStatus(a.status) === 'stale').length;
  const deadCount = agentList.filter((a) => normalizeStatus(a.status) === 'dead').length;
  const totalTps = agentList.reduce((s, a) => s + (a.tps ?? 0), 0);
  const totalActiveRoutes = agentList.reduce((s, a) => s + (a.activeRoutes ?? 0), 0);
  const totalRoutes = agentList.reduce((s, a) => s + (a.totalRoutes ?? 0), 0);

  // Map events to FeedEvent
  const feedEvents: FeedEvent[] = useMemo(() => {
    const mapped = (events ?? []).map((e: { id: number; instanceId: string; eventType: string; detail: string; timestamp: string }) => ({
      id: String(e.id),
      severity: eventSeverity(e.eventType),
      icon: eventIcon(e.eventType),
      message: `${e.instanceId}: ${e.eventType}${e.detail ? ' \u2014 ' + e.detail : ''}`,
      timestamp: new Date(e.timestamp),
    }));
    return eventSortAsc ? mapped.toReversed() : mapped;
  }, [events, eventSortAsc]);

  // Column definitions for the instance DataTable
  const instanceColumns: Column<AgentInstance>[] = useMemo(
    () => [
      {
        key: 'status',
        header: '',
        width: '12px',
        render: (_val, row) => <StatusDot variant={normalizeStatus(row.status)} />,
      },
      {
        key: '_inspect',
        header: '',
        width: '36px',
        render: (_val, row) => (
          <button
            className={styles.inspectLink}
            title="Open instance page"
            onClick={(e) => {
              e.stopPropagation();
              navigate(`/agents/${row.applicationId}/${row.instanceId}`);
            }}
          >
            <ExternalLink size={14} />
          </button>
        ),
      },
      {
        key: 'name',
        header: 'Instance',
        render: (_val, row) => (
          <MonoText size="sm" className={styles.instanceName}>{row.displayName ?? row.instanceId}</MonoText>
        ),
      },
      {
        key: 'state',
        header: 'State',
        render: (_val, row) => {
          const ns = normalizeStatus(row.status);
          return <Badge label={row.status} color={statusColor(ns)} variant="filled" />;
        },
      },
      {
        key: 'uptime',
        header: 'Uptime',
        render: (_val, row) => (
          <MonoText size="xs" className={styles.instanceMeta}>{formatUptime(row.uptimeSeconds)}</MonoText>
        ),
      },
      {
        key: 'tps',
        header: 'TPS',
        render: (_val, row) => (
          <MonoText size="xs" className={styles.instanceMeta}>
            {row.tps != null ? `${row.tps.toFixed(1)}/s` : '\u2014'}
          </MonoText>
        ),
      },
      {
        key: 'errorRate',
        header: 'Errors',
        render: (_val, row) => (
          <MonoText size="xs" className={row.errorRate ? styles.instanceError : styles.instanceMeta}>
            {formatErrorRate(row.errorRate)}
          </MonoText>
        ),
      },
      {
        key: 'lastHeartbeat',
        header: 'Heartbeat',
        render: (_val, row) => {
          const ns = normalizeStatus(row.status);
          return (
            <MonoText
              size="xs"
              className={
                ns === 'dead'
                  ? styles.instanceHeartbeatDead
                  : ns === 'stale'
                    ? styles.instanceHeartbeatStale
                    : styles.instanceMeta
              }
            >
              {timeAgo(row.lastHeartbeat)}
            </MonoText>
          );
        },
      },
    ],
    [],
  );

  function handleInstanceClick(inst: AgentInstance) {
    navigate(`/runtime/${inst.applicationId}/${inst.instanceId}`);
  }

  const isFullWidth = !!appId;

  return (
    <div className={styles.content}>
      {/* No agents warning + dismiss — shown when app-scoped, no agents, admin */}
      {appId && agentList.length === 0 && isAdmin && (
        <>
          <Alert variant="warning" title="No agents connected" className={styles.dismissAlert}>
            <span>
              {catalogEntry?.managed ? 'Managed app' : 'Discovered app'} &mdash; {(catalogEntry?.exchangeCount ?? 0).toLocaleString()} exchanges recorded.
              {' '}You can dismiss this application to remove it and all associated data.
            </span>
            <div style={{ marginTop: 8 }}>
              <Button variant="danger" size="sm" disabled={dismissApp.isPending}
                onClick={() => setConfirmDismissOpen(true)}>
                {dismissApp.isPending ? 'Dismissing\u2026' : 'Dismiss Application'}
              </Button>
            </div>
          </Alert>
          <ConfirmDialog
            open={confirmDismissOpen}
            onClose={() => setConfirmDismissOpen(false)}
            onConfirm={() => {
              setConfirmDismissOpen(false);
              dismissApp.mutate(appId, {
                onSuccess: () => {
                  toast({ title: 'Application dismissed', description: `${appId} and all associated data have been deleted`, variant: 'success' });
                  navigate('/runtime');
                },
                onError: (err) => {
                  toast({ title: 'Dismiss failed', description: err.message, variant: 'error', duration: 86_400_000 });
                },
              });
            }}
            title="Dismiss Application"
            message={`This will permanently delete "${appId}" and all associated data (${(catalogEntry?.exchangeCount ?? 0).toLocaleString()} exchanges, logs, diagrams). This action cannot be undone.`}
            confirmText={appId}
            confirmLabel="Dismiss"
            variant="danger"
            loading={dismissApp.isPending}
          />
        </>
      )}

      {/* Stat strip */}
      <div className={styles.statStrip}>
        <StatCard
          label="Total Agents"
          value={String(totalInstances)}
          accent={deadCount > 0 ? 'warning' : 'amber'}
          detail={
            <span className={styles.breakdown}>
              <span className={styles.bpLive}><StatusDot variant="live" /> {liveCount} live</span>
              <span className={styles.bpStale}><StatusDot variant="stale" /> {staleCount} stale</span>
              <span className={styles.bpDead}><StatusDot variant="dead" /> {deadCount} dead</span>
            </span>
          }
        />
        <StatCard
          label="Applications"
          value={String(groups.length)}
          accent="running"
          detail={
            <span className={styles.breakdown}>
              <span className={styles.bpLive}>
                <StatusDot variant="live" /> {groups.filter((g) => g.deadCount === 0 && g.staleCount === 0).length} healthy
              </span>
              <span className={styles.bpStale}>
                <StatusDot variant="stale" /> {groups.filter((g) => g.staleCount > 0 && g.deadCount === 0).length} degraded
              </span>
              <span className={styles.bpDead}>
                <StatusDot variant="dead" /> {groups.filter((g) => g.deadCount > 0).length} critical
              </span>
            </span>
          }
        />
        <StatCard
          label="Active Routes"
          value={
            <span
              className={
                styles[
                  totalActiveRoutes === 0
                    ? 'routesError'
                    : totalActiveRoutes < totalRoutes
                      ? 'routesWarning'
                      : 'routesSuccess'
                ]
              }
            >
              {totalActiveRoutes}/{totalRoutes}
            </span>
          }
          accent={totalActiveRoutes === 0 ? 'error' : totalActiveRoutes < totalRoutes ? 'warning' : 'success'}
          detail={totalActiveRoutes < totalRoutes ? `${totalRoutes - totalActiveRoutes} suspended` : 'all routes active'}
        />
        <StatCard
          label="Total TPS"
          value={totalTps.toFixed(1)}
          accent="amber"
          detail="msg/s"
        />
        <StatCard
          label="Dead"
          value={String(deadCount)}
          accent={deadCount > 0 ? 'error' : 'success'}
          detail={deadCount > 0 ? 'requires attention' : 'all healthy'}
        />
      </div>

      {/* View toolbar */}
      <div className={styles.viewToolbar}>
        <div className={styles.viewToggle}>
          <button
            className={`${styles.viewToggleBtn} ${viewMode === 'compact' ? styles.viewToggleBtnActive : ''}`}
            onClick={() => toggleViewMode('compact')}
            title="Compact view"
          >
            <LayoutGrid size={14} />
          </button>
          <button
            className={`${styles.viewToggleBtn} ${viewMode === 'expanded' ? styles.viewToggleBtnActive : ''}`}
            onClick={() => toggleViewMode('expanded')}
            title="Expanded view"
          >
            <List size={14} />
          </button>
        </div>
      </div>

      {/* Application config bar */}
      {appId && appConfig && (
        <div className={`${sectionStyles.section} ${styles.configBar}`}>
          {configEditing ? (
            <>
              <div className={styles.configField}>
                <span className={styles.configLabel}>App Log Level</span>
                <Select value={String(configDraft.applicationLogLevel ?? 'INFO')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, applicationLogLevel: e.target.value }))}
                  options={[
                    { value: 'ERROR', label: 'ERROR' },
                    { value: 'WARN', label: 'WARN' },
                    { value: 'INFO', label: 'INFO' },
                    { value: 'DEBUG', label: 'DEBUG' },
                    { value: 'TRACE', label: 'TRACE' },
                  ]}
                />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Agent Log Level</span>
                <Select value={String(configDraft.agentLogLevel ?? 'INFO')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, agentLogLevel: e.target.value }))}
                  options={[
                    { value: 'ERROR', label: 'ERROR' },
                    { value: 'WARN', label: 'WARN' },
                    { value: 'INFO', label: 'INFO' },
                    { value: 'DEBUG', label: 'DEBUG' },
                    { value: 'TRACE', label: 'TRACE' },
                  ]}
                />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Engine Level</span>
                <Select value={String(configDraft.engineLevel ?? 'REGULAR')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, engineLevel: e.target.value }))}
                  options={[
                    { value: 'NONE', label: 'None' },
                    { value: 'MINIMAL', label: 'Minimal' },
                    { value: 'REGULAR', label: 'Regular' },
                    { value: 'COMPLETE', label: 'Complete' },
                  ]}
                />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Payload Capture</span>
                <Select value={String(configDraft.payloadCaptureMode ?? 'BOTH')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, payloadCaptureMode: e.target.value }))}
                  options={[
                    { value: 'NONE', label: 'None' },
                    { value: 'INPUT', label: 'Input' },
                    { value: 'OUTPUT', label: 'Output' },
                    { value: 'BOTH', label: 'Both' },
                  ]}
                />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Metrics</span>
                <Toggle checked={Boolean(configDraft.metricsEnabled)}
                  onChange={(e) => setConfigDraft(d => ({ ...d, metricsEnabled: (e.target as HTMLInputElement).checked }))} />
              </div>
              <div className={styles.configActions}>
                <Button variant="primary" size="sm" onClick={saveConfigEdit} disabled={updateConfig.isPending}>Save</Button>
                <Button variant="secondary" size="sm" onClick={() => { setConfigEditing(false); setConfigDraft({}); }}>Cancel</Button>
              </div>
            </>
          ) : (
            <>
              <div className={styles.configField}>
                <span className={styles.configLabel}>App Log Level</span>
                <Badge label={appConfig.applicationLogLevel ?? 'INFO'} color={
                  (appConfig.applicationLogLevel ?? 'INFO') === 'ERROR' ? 'error'
                  : (appConfig.applicationLogLevel ?? 'INFO') === 'WARN' ? 'warning'
                  : (appConfig.applicationLogLevel ?? 'INFO') === 'DEBUG' ? 'running'
                  : (appConfig.applicationLogLevel ?? 'INFO') === 'TRACE' ? 'auto' : 'success'
                } variant="filled" />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Agent Log Level</span>
                <Badge label={appConfig.agentLogLevel ?? 'INFO'} color={
                  (appConfig.agentLogLevel ?? 'INFO') === 'ERROR' ? 'error'
                  : (appConfig.agentLogLevel ?? 'INFO') === 'WARN' ? 'warning'
                  : (appConfig.agentLogLevel ?? 'INFO') === 'DEBUG' ? 'running'
                  : (appConfig.agentLogLevel ?? 'INFO') === 'TRACE' ? 'auto' : 'success'
                } variant="filled" />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Engine Level</span>
                <Badge label={appConfig.engineLevel ?? 'REGULAR'} color={
                  (appConfig.engineLevel ?? 'REGULAR') === 'NONE' ? 'error'
                  : (appConfig.engineLevel ?? 'REGULAR') === 'MINIMAL' ? 'warning'
                  : (appConfig.engineLevel ?? 'REGULAR') === 'COMPLETE' ? 'running' : 'success'
                } variant="filled" />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Payload Capture</span>
                <Badge label={appConfig.payloadCaptureMode ?? 'BOTH'} color={
                  (appConfig.payloadCaptureMode ?? 'BOTH') === 'BOTH' ? 'running'
                  : (appConfig.payloadCaptureMode ?? 'BOTH') === 'NONE' ? 'auto' : 'warning'
                } variant="filled" />
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Metrics</span>
                <Badge label={appConfig.metricsEnabled ? 'On' : 'Off'} color={appConfig.metricsEnabled ? 'success' : 'error'} variant="filled" />
              </div>
              <Button variant="ghost" size="sm" title="Edit config" onClick={startConfigEdit}><Pencil size={14} /></Button>
            </>
          )}
        </div>
      )}


      {/* Group cards grid */}
      {viewMode === 'expanded' || isFullWidth ? (
        <div className={isFullWidth ? styles.groupGridSingle : styles.groupGrid}>
          {groups.map((group) => (
            <GroupCard
              key={group.appId}
              title={group.appId}
              accent={appHealth(group)}
              headerRight={
                <Badge
                  label={`${group.liveCount}/${group.instances.length} LIVE`}
                  color={appHealth(group)}
                  variant="filled"
                />
              }
              meta={
                <div className={styles.groupMeta}>
                  <span><strong>{group.totalTps.toFixed(1)}</strong> msg/s</span>
                  <span><strong>{group.totalActiveRoutes}</strong>/{group.totalRoutes} routes</span>
                  <span>
                    <StatusDot
                      variant={
                        appHealth(group) === 'success'
                          ? 'live'
                          : appHealth(group) === 'warning'
                            ? 'stale'
                            : 'dead'
                      }
                    />
                  </span>
                </div>
              }
              footer={
                group.deadCount > 0 ? (
                  <div className={styles.alertBanner}>
                    <span className={styles.alertIcon}>&#9888;</span>
                    <span>
                      Single point of failure &mdash;{' '}
                      {group.deadCount === group.instances.length
                        ? 'no redundancy'
                        : `${group.deadCount} dead instance${group.deadCount > 1 ? 's' : ''}`}
                    </span>
                  </div>
                ) : undefined
              }
            >
              <DataTable<AgentInstance & { id: string }>
                columns={instanceColumns as Column<AgentInstance & { id: string }>[]}
                data={group.instances.map(i => ({ ...i, id: i.instanceId }))}
                onRowClick={handleInstanceClick}
                pageSize={50}
                flush
              />
            </GroupCard>
          ))}
        </div>
      ) : (
        <div className={styles.compactGrid}>
          {groups.map((group) => (
            <div key={group.appId} className={styles.compactGridCell}>
              <CompactAppCard
                group={group}
                onExpand={() => animateToggle(group.appId)}
                onNavigate={() => navigate(`/runtime/${group.appId}`)}
              />
              {expandedApps.has(group.appId) && (
                <div
                  ref={(el) => {
                    if (!el) return;
                    // Constrain overlay within viewport
                    const rect = el.getBoundingClientRect();
                    const vw = document.documentElement.clientWidth;
                    if (rect.right > vw - 16) {
                      el.style.left = 'auto';
                      el.style.right = '0';
                    }
                    if (rect.bottom > document.documentElement.clientHeight) {
                      const overflow = rect.bottom - document.documentElement.clientHeight + 16;
                      el.style.maxHeight = `${rect.height - overflow}px`;
                      el.style.overflowY = 'auto';
                    }
                  }}
                  className={`${styles.compactGridExpanded} ${styles.expandWrapper} ${
                    animatingApps.get(group.appId) === 'expanding'
                      ? styles.expandWrapperCollapsed
                      : animatingApps.get(group.appId) === 'collapsing'
                        ? styles.expandWrapperCollapsed
                        : styles.expandWrapperExpanded
                  }`}
                >
                  <GroupCard
                    title={group.appId}
                    accent={appHealth(group)}
                    headerRight={
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <Badge
                          label={`${group.liveCount}/${group.instances.length} LIVE`}
                          color={appHealth(group)}
                          variant="filled"
                        />
                        <button
                          className={styles.collapseBtn}
                          onClick={() => animateToggle(group.appId)}
                          title="Collapse"
                        >
                          <ChevronDown size={14} />
                        </button>
                      </div>
                    }
                    meta={
                      <div className={styles.groupMeta}>
                        <span><strong>{group.totalTps.toFixed(1)}</strong> msg/s</span>
                        <span><strong>{group.totalActiveRoutes}</strong>/{group.totalRoutes} routes</span>
                        <span>
                          <StatusDot
                            variant={
                              appHealth(group) === 'success'
                                ? 'live'
                                : appHealth(group) === 'warning'
                                  ? 'stale'
                                  : 'dead'
                            }
                          />
                        </span>
                      </div>
                    }
                    footer={
                      group.deadCount > 0 ? (
                        <div className={styles.alertBanner}>
                          <span className={styles.alertIcon}>&#9888;</span>
                          <span>
                            Single point of failure &mdash;{' '}
                            {group.deadCount === group.instances.length
                              ? 'no redundancy'
                              : `${group.deadCount} dead instance${group.deadCount > 1 ? 's' : ''}`}
                          </span>
                        </div>
                      ) : undefined
                    }
                  >
                    <DataTable<AgentInstance & { id: string }>
                      columns={instanceColumns as Column<AgentInstance & { id: string }>[]}
                      data={group.instances.map(i => ({ ...i, id: i.instanceId }))}
                      onRowClick={handleInstanceClick}
                      pageSize={50}
                      flush
                    />
                  </GroupCard>
                </div>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Log + Timeline side by side */}
      <div className={styles.bottomRow}>
        <div className={logStyles.logCard}>
          <div className={logStyles.logHeader}>
            <SectionHeader>Application Log</SectionHeader>
            <div className={logStyles.headerActions}>
              <span className={styles.sectionMeta}>{logEntries.length} entries</span>
              <Button variant="ghost" size="sm" onClick={() => setLogSortAsc((v) => !v)} title={logSortAsc ? 'Oldest first' : 'Newest first'}>
                {logSortAsc ? '\u2191' : '\u2193'}
              </Button>
              <Button variant="ghost" size="sm" onClick={() => setLogRefreshTo(new Date().toISOString())} title="Refresh">
                <RefreshCw size={14} />
              </Button>
            </div>
          </div>
          <div className={logStyles.logToolbar}>
            <div className={logStyles.logSearchWrap}>
              <input
                type="text"
                className={logStyles.logSearchInput}
                placeholder="Search logs\u2026"
                value={logSearch}
                onChange={(e) => setLogSearch(e.target.value)}
                aria-label="Search logs"
              />
              {logSearch && (
                <button
                  type="button"
                  className={logStyles.logSearchClear}
                  onClick={() => setLogSearch('')}
                  aria-label="Clear search"
                >
                  &times;
                </button>
              )}
            </div>
            <ButtonGroup
              items={LOG_SOURCE_ITEMS}
              value={logSource ? new Set([logSource]) : new Set()}
              onChange={(v) => setLogSource(v.size === 0 ? '' : [...v][0])}
            />
            <ButtonGroup items={LOG_LEVEL_ITEMS} value={logLevels} onChange={setLogLevels} />
            {logLevels.size > 0 && (
              <Button variant="ghost" size="sm" onClick={() => setLogLevels(new Set())}>
                Clear
              </Button>
            )}
          </div>
          {filteredLogs.length > 0 ? (
            <LogViewer entries={filteredLogs} maxHeight={360} />
          ) : (
            <div className={logStyles.logEmpty}>
              {logSearch || logLevels.size > 0 ? 'No matching log entries' : 'No log entries available'}
            </div>
          )}
        </div>

        <div className={`${sectionStyles.section} ${styles.eventCard}`}>
          <div className={styles.eventCardHeader}>
            <span className={styles.sectionTitle}>Timeline</span>
            <div className={logStyles.headerActions}>
              <span className={styles.sectionMeta}>{feedEvents.length} events</span>
              <Button variant="ghost" size="sm" onClick={() => setEventSortAsc((v) => !v)} title={eventSortAsc ? 'Oldest first' : 'Newest first'}>
                {eventSortAsc ? '\u2191' : '\u2193'}
              </Button>
              <Button variant="ghost" size="sm" onClick={() => setEventRefreshTo(new Date().toISOString())} title="Refresh">
                <RefreshCw size={14} />
              </Button>
            </div>
          </div>
          {feedEvents.length > 0 ? (
            <EventFeed events={feedEvents} maxItems={100} />
          ) : (
            <div className={logStyles.logEmpty}>No events in the selected time range.</div>
          )}
        </div>
      </div>

    </div>
  );
}
