import { useState, useMemo, useCallback } from 'react';
import { useParams, useNavigate } from 'react-router';
import {
  StatCard, StatusDot, Badge, MonoText, ProgressBar,
  GroupCard, DataTable, LineChart, EventFeed, DetailPanel,
  LogViewer, ButtonGroup, SectionHeader, Toggle, useToast,
} from '@cameleer/design-system';
import type { Column, FeedEvent, LogEntry, ButtonGroupItem } from '@cameleer/design-system';
import styles from './AgentHealth.module.css';
import { useAgents, useAgentEvents } from '../../api/queries/agents';
import { useApplicationLogs } from '../../api/queries/logs';
import { useAgentMetrics } from '../../api/queries/agent-metrics';
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
import type { AgentInstance } from '../../api/types';

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

function timeAgo(iso?: string): string {
  if (!iso) return '\u2014';
  const diff = Date.now() - new Date(iso).getTime();
  const secs = Math.floor(diff / 1000);
  if (secs < 60) return `${secs}s ago`;
  const mins = Math.floor(secs / 60);
  if (mins < 60) return `${mins}m ago`;
  const hours = Math.floor(mins / 60);
  if (hours < 24) return `${hours}h ago`;
  return `${Math.floor(hours / 24)}d ago`;
}

function formatUptime(seconds?: number): string {
  if (!seconds) return '\u2014';
  const days = Math.floor(seconds / 86400);
  const hours = Math.floor((seconds % 86400) / 3600);
  const mins = Math.floor((seconds % 3600) / 60);
  if (days > 0) return `${days}d ${hours}h`;
  if (hours > 0) return `${hours}h ${mins}m`;
  return `${mins}m`;
}

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.application;
    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';
}

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

function AgentOverviewContent({ agent }: { agent: AgentInstance }) {
  const { data: memMetrics } = useAgentMetrics(
    agent.id,
    ['jvm.memory.heap.used', 'jvm.memory.heap.max'],
    1,
  );
  const { data: cpuMetrics } = useAgentMetrics(agent.id, ['jvm.cpu.process'], 1);

  const cpuValue = cpuMetrics?.metrics?.['jvm.cpu.process']?.[0]?.value;
  const heapUsed = memMetrics?.metrics?.['jvm.memory.heap.used']?.[0]?.value;
  const heapMax = memMetrics?.metrics?.['jvm.memory.heap.max']?.[0]?.value;

  const heapPercent =
    heapUsed != null && heapMax != null && heapMax > 0
      ? Math.round((heapUsed / heapMax) * 100)
      : undefined;
  const cpuPercent = cpuValue != null ? Math.round(cpuValue * 100) : undefined;

  const ns = normalizeStatus(agent.status);

  return (
    <div className={styles.detailContent}>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Status</span>
        <Badge label={agent.status} color={statusColor(ns)} variant="filled" />
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Application</span>
        <MonoText size="xs">{agent.application}</MonoText>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Uptime</span>
        <MonoText size="xs">{formatUptime(agent.uptimeSeconds)}</MonoText>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Last Seen</span>
        <MonoText size="xs">{timeAgo(agent.lastHeartbeat)}</MonoText>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Throughput</span>
        <MonoText size="xs">{agent.tps != null ? `${agent.tps.toFixed(1)}/s` : '\u2014'}</MonoText>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Errors</span>
        <MonoText size="xs" className={agent.errorRate ? styles.instanceError : undefined}>
          {formatErrorRate(agent.errorRate)}
        </MonoText>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Routes</span>
        <span>{agent.activeRoutes ?? 0}/{agent.totalRoutes ?? 0} active</span>
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>Heap Memory</span>
        {heapPercent != null ? (
          <div className={styles.detailProgress}>
            <ProgressBar
              value={heapPercent}
              variant={heapPercent > 85 ? 'error' : heapPercent > 70 ? 'warning' : 'success'}
              size="sm"
            />
            <MonoText size="xs">{heapPercent}%</MonoText>
          </div>
        ) : (
          <MonoText size="xs">N/A</MonoText>
        )}
      </div>
      <div className={styles.detailRow}>
        <span className={styles.detailLabel}>CPU</span>
        {cpuPercent != null ? (
          <div className={styles.detailProgress}>
            <ProgressBar
              value={cpuPercent}
              variant={cpuPercent > 80 ? 'error' : cpuPercent > 60 ? 'warning' : 'success'}
              size="sm"
            />
            <MonoText size="xs">{cpuPercent}%</MonoText>
          </div>
        ) : (
          <MonoText size="xs">N/A</MonoText>
        )}
      </div>
    </div>
  );
}

function AgentPerformanceContent({ agent }: { agent: AgentInstance }) {
  const { data: tpsMetrics } = useAgentMetrics(agent.id, ['cameleer.tps'], 60);
  const { data: errMetrics } = useAgentMetrics(agent.id, ['cameleer.error.rate'], 60);

  const tpsSeries = useMemo(() => {
    const raw = tpsMetrics?.metrics?.['cameleer.tps'] ?? [];
    return [{ label: 'TPS', data: raw.map((p) => ({ x: new Date(p.time), y: p.value })) }];
  }, [tpsMetrics]);

  const errSeries = useMemo(() => {
    const raw = errMetrics?.metrics?.['cameleer.error.rate'] ?? [];
    return [{
      label: 'Error Rate',
      data: raw.map((p) => ({ x: new Date(p.time), y: p.value * 100 })),
      color: 'var(--error)',
    }];
  }, [errMetrics]);

  return (
    <div className={styles.detailContent}>
      <div className={styles.chartPanel}>
        <div className={styles.chartTitle}>Throughput (msg/s)</div>
        {tpsSeries[0].data.length > 0 ? (
          <LineChart series={tpsSeries} height={160} yLabel="msg/s" />
        ) : (
          <div className={styles.emptyChart}>No data available</div>
        )}
      </div>
      <div className={styles.chartPanel}>
        <div className={styles.chartTitle}>Error Rate (%)</div>
        {errSeries[0].data.length > 0 ? (
          <LineChart series={errSeries} height={160} yLabel="%" />
        ) : (
          <div className={styles.emptyChart}>No data available</div>
        )}
      </div>
    </div>
  );
}

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)' },
];

function mapLogLevel(level: string): LogEntry['level'] {
  switch (level?.toUpperCase()) {
    case 'ERROR': return 'error';
    case 'WARN': case 'WARNING': return 'warn';
    case 'DEBUG': case 'TRACE': return 'debug';
    default: return 'info';
  }
}

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

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

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

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

  const saveConfigEdit = useCallback(() => {
    if (!appConfig) return;
    const updated = { ...appConfig, ...configDraft };
    updateConfig.mutate(updated, {
      onSuccess: (saved) => {
        setConfigEditing(false);
        setConfigDraft({});
        toast({ title: 'Config updated', description: `${appId} (v${saved.version})`, variant: 'success' });
      },
      onError: () => {
        toast({ title: 'Config update failed', variant: 'error' });
      },
    });
  }, [appConfig, configDraft, updateConfig, toast, appId]);
  const [eventSortAsc, setEventSortAsc] = useState(false);
  const [eventRefreshTo, setEventRefreshTo] = useState<string | undefined>();
  const { data: events } = useAgentEvents(appId, undefined, 50, eventRefreshTo);

  const [logSearch, setLogSearch] = useState('');
  const [logLevels, setLogLevels] = useState<Set<string>>(new Set());
  const [logSortAsc, setLogSortAsc] = useState(false);
  const [logRefreshTo, setLogRefreshTo] = useState<string | undefined>();
  const { data: rawLogs } = useApplicationLogs(appId, undefined, { toOverride: logRefreshTo });
  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 [selectedInstance, setSelectedInstance] = useState<AgentInstance | null>(null);
  const [panelOpen, setPanelOpen] = useState(false);

  const agentList = agents ?? [];

  const groups = useMemo(() => groupByApp(agentList), [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; agentId: string; eventType: string; detail: string; timestamp: string }) => ({
      id: String(e.id),
      severity:
        e.eventType === 'WENT_DEAD'
          ? ('error' as const)
          : e.eventType === 'WENT_STALE'
            ? ('warning' as const)
            : e.eventType === 'RECOVERED'
              ? ('success' as const)
              : ('running' as const),
      message: `${e.agentId}: ${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.application}/${row.id}`);
            }}
          >
            &#x2197;
          </button>
        ),
      },
      {
        key: 'name',
        header: 'Instance',
        render: (_val, row) => (
          <MonoText size="sm" className={styles.instanceName}>{row.name ?? row.id}</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) {
    setSelectedInstance(inst);
    setPanelOpen(true);
  }

  // Detail panel tabs
  const detailTabs = selectedInstance
    ? [
        {
          label: 'Overview',
          value: 'overview',
          content: <AgentOverviewContent agent={selectedInstance} />,
        },
        {
          label: 'Performance',
          value: 'performance',
          content: <AgentPerformanceContent agent={selectedInstance} />,
        },
      ]
    : [];

  const isFullWidth = !!appId;

  return (
    <div className={styles.content}>
      {/* 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>

      <div style={{ marginBottom: 12 }}>
        <Badge
          label={`${liveCount}/${totalInstances} live`}
          color={deadCount > 0 ? 'error' : staleCount > 0 ? 'warning' : 'success'}
          variant="filled"
        />
      </div>

      {/* Application config bar */}
      {appId && appConfig && (
        <div className={styles.configBar}>
          {configEditing ? (
            <>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Log Level</span>
                <select className={styles.configSelect} value={String(configDraft.logForwardingLevel ?? 'INFO')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, logForwardingLevel: e.target.value }))}>
                  <option value="ERROR">ERROR</option>
                  <option value="WARN">WARN</option>
                  <option value="INFO">INFO</option>
                  <option value="DEBUG">DEBUG</option>
                </select>
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Engine Level</span>
                <select className={styles.configSelect} value={String(configDraft.engineLevel ?? 'REGULAR')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, engineLevel: e.target.value }))}>
                  <option value="NONE">None</option>
                  <option value="MINIMAL">Minimal</option>
                  <option value="REGULAR">Regular</option>
                  <option value="COMPLETE">Complete</option>
                </select>
              </div>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Payload Capture</span>
                <select className={styles.configSelect} value={String(configDraft.payloadCaptureMode ?? 'NONE')}
                  onChange={(e) => setConfigDraft(d => ({ ...d, payloadCaptureMode: e.target.value }))}>
                  <option value="NONE">None</option>
                  <option value="INPUT">Input</option>
                  <option value="OUTPUT">Output</option>
                  <option value="BOTH">Both</option>
                </select>
              </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 className={styles.configSaveBtn} onClick={saveConfigEdit} disabled={updateConfig.isPending}>Save</button>
                <button className={styles.configCancelBtn} onClick={() => { setConfigEditing(false); setConfigDraft({}); }}>Cancel</button>
              </div>
            </>
          ) : (
            <>
              <div className={styles.configField}>
                <span className={styles.configLabel}>Log Level</span>
                <Badge label={appConfig.logForwardingLevel ?? 'INFO'} color={
                  (appConfig.logForwardingLevel ?? 'INFO') === 'ERROR' ? 'error'
                  : (appConfig.logForwardingLevel ?? 'INFO') === 'WARN' ? 'warning'
                  : (appConfig.logForwardingLevel ?? 'INFO') === 'DEBUG' ? 'running' : '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 ?? 'NONE'} color={
                  (appConfig.payloadCaptureMode ?? 'NONE') === 'BOTH' ? 'running'
                  : (appConfig.payloadCaptureMode ?? 'NONE') === '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 className={styles.configEditBtn} title="Edit config" onClick={startConfigEdit}>&#x270E;</button>
            </>
          )}
        </div>
      )}

      {/* Group cards grid */}
      <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>
              columns={instanceColumns}
              data={group.instances}
              onRowClick={handleInstanceClick}
              selectedId={panelOpen ? selectedInstance?.id : undefined}
              pageSize={50}
              flush
            />
          </GroupCard>
        ))}
      </div>

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

        <div className={styles.eventCard}>
          <div className={styles.eventCardHeader}>
            <span className={styles.sectionTitle}>Timeline</span>
            <div className={styles.headerActions}>
              <span className={styles.sectionMeta}>{feedEvents.length} events</span>
              <button className={styles.sortBtn} onClick={() => setEventSortAsc((v) => !v)} title={eventSortAsc ? 'Oldest first' : 'Newest first'}>
                {eventSortAsc ? '\u2191' : '\u2193'}
              </button>
              <button className={styles.refreshBtn} onClick={() => setEventRefreshTo(new Date().toISOString())} title="Refresh">
                &#x21bb;
              </button>
            </div>
          </div>
          {feedEvents.length > 0 ? (
            <EventFeed events={feedEvents} maxItems={100} />
          ) : (
            <div className={styles.logEmpty}>No events in the selected time range.</div>
          )}
        </div>
      </div>

      {/* Detail panel — auto-portals to AppShell level via design system */}
      {selectedInstance && (
        <DetailPanel
          open={panelOpen}
          onClose={() => { setPanelOpen(false); setSelectedInstance(null); }}
          title={selectedInstance.name ?? selectedInstance.id}
          tabs={detailTabs}
        />
      )}
    </div>
  );
}
