import { useMemo, useRef, useState } from 'react';
import { useParams } from 'react-router';
import { RefreshCw } from 'lucide-react';
import { useInfiniteApplicationLogs } from '../../api/queries/logs';
import { useInfiniteAgentEvents } from '../../api/queries/agents';
import { InfiniteScrollArea } from '../../components/InfiniteScrollArea';
import {
  StatCard, StatusDot, Badge, ThemedChart, Line, Area, ReferenceLine, CHART_COLORS,
  EventFeed, Spinner, EmptyState, SectionHeader, MonoText,
  LogViewer, ButtonGroup, useGlobalFilters,
} from '@cameleer/design-system';
import type { FeedEvent, LogEntry, ButtonGroupItem } from '@cameleer/design-system';
import styles from './AgentInstance.module.css';
import sectionStyles from '../../styles/section-card.module.css';
import logStyles from '../../styles/log-panel.module.css';
import chartCardStyles from '../../styles/chart-card.module.css';
import { useAgents } from '../../api/queries/agents';
import { useAgentMetrics } from '../../api/queries/agent-metrics';
import { formatUptime, mapLogLevel, eventSeverity, eventIcon } from '../../utils/agent-utils';
import { useEnvironmentStore } from '../../api/environment-store';

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

export default function AgentInstance() {
  const { appId, instanceId } = useParams();
  const { timeRange } = useGlobalFilters();
  const [logSearch, setLogSearch] = useState('');
  const [logLevels, setLogLevels] = useState<Set<string>>(new Set());
  const [logSources, setLogSources] = useState<Set<string>>(new Set());
  const [logSortAsc, setLogSortAsc] = useState(false);
  const [eventSortAsc, setEventSortAsc] = useState(false);
  const [isLogAtTop, setIsLogAtTop] = useState(true);
  const logScrollRef = useRef<HTMLDivElement | null>(null);
  const timeFrom = timeRange.start.toISOString();
  const timeTo = timeRange.end.toISOString();

  const selectedEnv = useEnvironmentStore((s) => s.environment);
  const { data: agents, isLoading } = useAgents(undefined, appId);
  const eventStream = useInfiniteAgentEvents({ appId, agentId: instanceId, isAtTop: true });

  const agent = useMemo(
    () => (agents || []).find((a: any) => a.instanceId === instanceId) as any,
    [agents, instanceId],
  );

  // Stat card metrics (latest 1 bucket)
  const { data: latestMetrics } = useAgentMetrics(
    agent?.instanceId || null,
    ['process.cpu.usage.value', 'jvm.memory.used.value', 'jvm.memory.max.value'],
    1,
    timeFrom, timeTo,
  );
  const cpuPct = latestMetrics?.metrics?.['process.cpu.usage.value']?.[0]?.value;
  const heapUsed = latestMetrics?.metrics?.['jvm.memory.used.value']?.[0]?.value;
  const heapMax = latestMetrics?.metrics?.['jvm.memory.max.value']?.[0]?.value;
  const memPct = heapMax ? (heapUsed! / heapMax) * 100 : undefined;

  // Chart metrics (60 buckets, time-range-aware)
  const { data: jvmMetrics } = useAgentMetrics(
    agent?.instanceId || null,
    ['process.cpu.usage.value', 'jvm.memory.used.value', 'jvm.memory.max.value', 'jvm.threads.live.value', 'jvm.gc.pause.total_time'],
    60, timeFrom, timeTo,
  );

  // Agent pipeline metrics (60 buckets, time-range-aware)
  const { data: agentMetrics } = useAgentMetrics(
    agent?.instanceId || null,
    ['cameleer.chunks.exported.count', 'cameleer.chunks.dropped.count'],
    60, timeFrom, timeTo, 'delta',
  );

  const feedEvents = useMemo<FeedEvent[]>(() => {
    const mapped = eventStream.items
      .filter((e) => !instanceId || e.instanceId === instanceId)
      .map((e) => ({
        id: `${e.timestamp}:${e.instanceId}:${e.eventType}`,
        severity: eventSeverity(e.eventType),
        icon: eventIcon(e.eventType),
        message: `${e.eventType}${e.detail ? ' \u2014 ' + e.detail : ''}`,
        timestamp: new Date(e.timestamp),
      }));
    return eventSortAsc ? mapped.toReversed() : mapped;
  }, [eventStream.items, instanceId, eventSortAsc]);

  const formatTime = (t: string) =>
    new Date(t).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });

  const cpuData = useMemo(() => {
    const pts = jvmMetrics?.metrics?.['process.cpu.usage.value'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, cpu: p.value * 100 }));
  }, [jvmMetrics]);

  const heapData = useMemo(() => {
    const pts = jvmMetrics?.metrics?.['jvm.memory.used.value'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, heap: p.value / (1024 * 1024) }));
  }, [jvmMetrics]);

  const threadData = useMemo(() => {
    const pts = jvmMetrics?.metrics?.['jvm.threads.live.value'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, threads: p.value }));
  }, [jvmMetrics]);

  const gcData = useMemo(() => {
    const pts = jvmMetrics?.metrics?.['jvm.gc.pause.total_time'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, gc: p.value }));
  }, [jvmMetrics]);

  const chunksExportedData = useMemo(() => {
    const pts = agentMetrics?.metrics?.['cameleer.chunks.exported.count'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, exported: p.value }));
  }, [agentMetrics]);

  const chunksDroppedData = useMemo(() => {
    const pts = agentMetrics?.metrics?.['cameleer.chunks.dropped.count'];
    if (!pts?.length) return [];
    return pts.map((p: any) => ({ time: p.time, dropped: p.value }));
  }, [agentMetrics]);

  // Application logs
  const logStream = useInfiniteApplicationLogs({
    application: appId,
    agentId: instanceId,
    sources: [...logSources],
    levels: [...logLevels],
    sort: logSortAsc ? 'asc' : 'desc',
    isAtTop: isLogAtTop,
  });
  const logEntries = useMemo<LogEntry[]>(() => {
    return logStream.items.map((l) => ({
      timestamp: l.timestamp ?? '',
      level: mapLogLevel(l.level),
      message: l.message ?? '',
      source: l.source ?? undefined,
    }));
  }, [logStream.items]);
  const searchLower = logSearch.toLowerCase();
  const filteredLogs = searchLower
    ? logEntries.filter((l) => l.message.toLowerCase().includes(searchLower))
    : logEntries;

  if (isLoading) return <Spinner size="lg" />;

  const statusVariant =
    agent?.status === 'LIVE' ? 'live' : agent?.status === 'STALE' ? 'stale' : 'dead';
  const statusColor: 'success' | 'warning' | 'error' =
    agent?.status === 'LIVE' ? 'success' : agent?.status === 'STALE' ? 'warning' : 'error';
  const cpuDisplay = cpuPct != null ? (cpuPct * 100).toFixed(0) : null;
  const heapUsedMB = heapUsed != null ? (heapUsed / (1024 * 1024)).toFixed(0) : null;
  const heapMaxMB = heapMax != null ? (heapMax / (1024 * 1024)).toFixed(0) : null;

  return (
    <div className={styles.content}>
      {/* Stat strip — 5 columns */}
      <div className={styles.statStrip}>
        <StatCard
          label="CPU"
          value={cpuDisplay != null ? `${cpuDisplay}%` : '\u2014'}
          accent={
            cpuDisplay != null
              ? Number(cpuDisplay) > 85
                ? 'error'
                : Number(cpuDisplay) > 70
                  ? 'warning'
                  : 'success'
              : undefined
          }
        />
        <StatCard
          label="Memory"
          value={memPct != null ? `${memPct.toFixed(0)}%` : '\u2014'}
          accent={
            memPct != null
              ? memPct > 85
                ? 'error'
                : memPct > 70
                  ? 'warning'
                  : 'success'
              : undefined
          }
          detail={
            heapUsedMB != null && heapMaxMB != null
              ? `${heapUsedMB} MB / ${heapMaxMB} MB`
              : undefined
          }
        />
        <StatCard
          label="Throughput"
          value={agent?.tps != null ? `${agent.tps.toFixed(1)}/s` : '\u2014'}
          accent="amber"
          detail="msg/s"
        />
        <StatCard
          label="Errors"
          value={agent?.errorRate != null ? `${(agent.errorRate * 100).toFixed(1)}%` : '\u2014'}
          accent={agent?.errorRate > 0 ? 'error' : 'success'}
        />
        <StatCard
          label="Uptime"
          value={formatUptime(agent?.uptimeSeconds)}
          accent="running"
          detail={
            agent?.registeredAt
              ? `since ${new Date(agent.registeredAt).toLocaleDateString()}`
              : undefined
          }
        />
      </div>

      {agent && (
        <>
          {/* Process info card */}
          <div className={`${sectionStyles.section} ${styles.processCard}`}>
            <SectionHeader>Process Information</SectionHeader>
            <div className={styles.processBadges}>
              <StatusDot variant={statusVariant} />
              <Badge label={agent.status} color={statusColor} />
              {agent.containerStatus && agent.containerStatus !== 'UNKNOWN' && (
                <Badge label={`Container: ${agent.containerStatus}`} variant="outlined" color="auto" />
              )}
              {agent.version && <Badge label={agent.version} variant="outlined" color="auto" />}
              <Badge
                label={`${agent.activeRoutes ?? (agent.routeIds?.length ?? 0)}/${agent.totalRoutes ?? (agent.routeIds?.length ?? 0)} routes`}
                color={
                  (agent.activeRoutes ?? 0) < (agent.totalRoutes ?? 0) ? 'warning' : 'success'
                }
              />
            </div>
            <div className={styles.processGrid}>
              {agent.capabilities?.jvmVersion && (
                <>
                  <span className={styles.processLabel}>JVM</span>
                  <MonoText size="xs">{agent.capabilities.jvmVersion}</MonoText>
                </>
              )}
              {agent.capabilities?.camelVersion && (
                <>
                  <span className={styles.processLabel}>Camel</span>
                  <MonoText size="xs">{agent.capabilities.camelVersion}</MonoText>
                </>
              )}
              {agent.capabilities?.springBootVersion && (
                <>
                  <span className={styles.processLabel}>Spring Boot</span>
                  <MonoText size="xs">{agent.capabilities.springBootVersion}</MonoText>
                </>
              )}
              <span className={styles.processLabel}>Started</span>
              <MonoText size="xs">
                {agent.registeredAt ? new Date(agent.registeredAt).toLocaleString() : '\u2014'}
              </MonoText>
              {agent.capabilities && (
                <>
                  <span className={styles.processLabel}>Capabilities</span>
                  <span className={styles.capTags}>
                    {Object.entries(agent.capabilities)
                      .filter(([, v]) => typeof v === 'boolean' && v)
                      .map(([k]) => (
                        <Badge key={k} label={k} variant="outlined" />
                      ))}
                  </span>
                </>
              )}
            </div>
          </div>


        </>
      )}

      {/* Charts grid — 3x2 */}
      <div className={styles.chartsGrid}>
        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>CPU Usage</span>
            <span className={styles.chartMeta}>
              {cpuDisplay != null ? `${cpuDisplay}% current` : ''}
            </span>
          </div>
          {cpuData.length ? (
            <ThemedChart data={cpuData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="%">
              <Area dataKey="cpu" name="CPU %" stroke={CHART_COLORS[0]}
                fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
              <ReferenceLine y={85} stroke="var(--error)" strokeDasharray="5 3"
                label={{ value: 'Alert', position: 'right', fill: 'var(--error)', fontSize: 9 }} />
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No CPU metrics available" />
          )}
        </div>

        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>Memory (Heap)</span>
            <span className={styles.chartMeta}>
              {heapUsedMB != null && heapMaxMB != null
                ? `${heapUsedMB} MB / ${heapMaxMB} MB`
                : ''}
            </span>
          </div>
          {heapData.length ? (
            <ThemedChart data={heapData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="MB">
              <Area dataKey="heap" name="Heap MB" stroke={CHART_COLORS[0]}
                fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
              {heapMax != null && (
                <ReferenceLine y={heapMax / (1024 * 1024)} stroke="var(--error)" strokeDasharray="5 3"
                  label={{ value: 'Max Heap', position: 'right', fill: 'var(--error)', fontSize: 9 }} />
              )}
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No heap metrics available" />
          )}
        </div>

        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>GC Pauses</span>
            <span className={styles.chartMeta} />
          </div>
          {gcData.length ? (
            <ThemedChart data={gcData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="ms">
              <Area dataKey="gc" name="GC ms" stroke={CHART_COLORS[1]}
                fill={CHART_COLORS[1]} fillOpacity={0.1} strokeWidth={2} dot={false} />
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No GC metrics available" />
          )}
        </div>

        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>Thread Count</span>
            <span className={styles.chartMeta}>
              {threadData.length
                ? `${threadData[threadData.length - 1].threads.toFixed(0)} active`
                : ''}
            </span>
          </div>
          {threadData.length ? (
            <ThemedChart data={threadData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="threads">
              <Line dataKey="threads" name="Threads" stroke={CHART_COLORS[0]}
                strokeWidth={2} dot={false} />
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No thread metrics available" />
          )}
        </div>

        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>Chunks Exported</span>
            <span className={styles.chartMeta} />
          </div>
          {chunksExportedData.length ? (
            <ThemedChart data={chunksExportedData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="chunks">
              <Area dataKey="exported" name="Exported" stroke={CHART_COLORS[0]}
                fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No chunk export metrics available" />
          )}
        </div>

        <div className={chartCardStyles.chartCard}>
          <div className={styles.chartHeader}>
            <span className={styles.chartTitle}>Chunks Dropped</span>
            <span className={styles.chartMeta} />
          </div>
          {chunksDroppedData.length ? (
            <ThemedChart data={chunksDroppedData} height={160} xDataKey="time"
              xTickFormatter={formatTime} yLabel="chunks">
              <Area dataKey="dropped" name="Dropped" stroke="var(--error)"
                fill="var(--error)" fillOpacity={0.1} strokeWidth={2} dot={false} />
            </ThemedChart>
          ) : (
            <EmptyState title="No data" description="No chunk drop metrics available" />
          )}
        </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.chartMeta}>
                {filteredLogs.length === logStream.items.length
                  ? `${filteredLogs.length} entries`
                  : `${filteredLogs.length} of ${logStream.items.length} entries`}
              </span>
              <button className={logStyles.sortBtn} onClick={() => setLogSortAsc((v) => !v)} title={logSortAsc ? 'Oldest first' : 'Newest first'}>
                {logSortAsc ? '\u2191' : '\u2193'}
              </button>
              <button className={logStyles.refreshBtn} onClick={() => {
                logStream.refresh();
                logScrollRef.current?.scrollTo({ top: 0 });
              }} 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…"
                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={logSources}
              onChange={setLogSources}
            />
            {logSources.size > 0 && (
              <button className={logStyles.logClearFilters} onClick={() => setLogSources(new Set())}>
                Clear
              </button>
            )}
            <ButtonGroup items={LOG_LEVEL_ITEMS} value={logLevels} onChange={setLogLevels} />
            {logLevels.size > 0 && (
              <button className={logStyles.logClearFilters} onClick={() => setLogLevels(new Set())}>
                Clear
              </button>
            )}
          </div>
          <InfiniteScrollArea
            scrollRef={logScrollRef}
            onEndReached={logStream.fetchNextPage}
            onTopVisibilityChange={setIsLogAtTop}
            isFetchingNextPage={logStream.isFetchingNextPage}
            hasNextPage={logStream.hasNextPage}
            isLoading={logStream.isLoading}
            hasItems={logStream.items.length > 0}
            maxHeight={360}
          >
            {filteredLogs.length > 0 ? (
              <LogViewer entries={filteredLogs} className={logStyles.flatScroll} />
            ) : (
              <div className={logStyles.logEmpty}>
                {logSearch || logLevels.size > 0 || logSources.size > 0
                  ? 'No matching log entries'
                  : logStream.isLoading ? 'Loading logs…' : 'No log entries available'}
              </div>
            )}
          </InfiniteScrollArea>
        </div>

        <div className={logStyles.logCard}>
          <div className={logStyles.logHeader}>
            <SectionHeader>Timeline</SectionHeader>
            <div className={logStyles.headerActions}>
              <span className={styles.chartMeta}>{eventStream.items.length} events</span>
              <button className={logStyles.sortBtn} onClick={() => setEventSortAsc((v) => !v)} title={eventSortAsc ? 'Oldest first' : 'Newest first'}>
                {eventSortAsc ? '\u2191' : '\u2193'}
              </button>
              <button className={logStyles.refreshBtn} onClick={() => eventStream.refresh()} title="Refresh">
                <RefreshCw size={14} />
              </button>
            </div>
          </div>
          <div className={logStyles.eventFeedContainer}>
            {feedEvents.length > 0 ? (
              <EventFeed events={feedEvents} />
            ) : (
              <div className={logStyles.logEmpty}>
                {eventStream.isLoading ? 'Loading events…' : 'No events in the selected time range.'}
              </div>
            )}
          </div>
          {eventStream.hasNextPage && (
            <button
              className={logStyles.loadOlderBtn}
              onClick={eventStream.fetchNextPage}
              disabled={eventStream.isFetchingNextPage}
            >
              {eventStream.isFetchingNextPage ? 'Loading…' : 'Load older events'}
            </button>
          )}
        </div>
      </div>
    </div>
  );
}
