import { useMemo } from 'react';
import {
  ThemedChart, Area, Line, CHART_COLORS,
  Badge, EmptyState, Spinner, useGlobalFilters,
} from '@cameleer/design-system';
import {
  useServerMetricsCatalog,
  useServerMetricsInstances,
  useServerMetricsSeries,
  type ServerMetricQueryResponse,
  type ServerMetricSeries,
  type ServerMetricsRange,
} from '../../api/queries/admin/serverMetrics';
import chartCardStyles from '../../styles/chart-card.module.css';
import styles from './ServerMetricsAdminPage.module.css';

// ── Step picker ────────────────────────────────────────────────────────

/**
 * Choose a bucket width that keeps the rendered series readable regardless
 * of the window size the global time-range control hands us.
 *
 * Targets roughly 30–120 points per series — any denser and the chart
 * becomes a blur; any sparser and short windows look empty. Clamped to the
 * [10, 3600] range the backend accepts.
 */
function stepSecondsFor(windowSeconds: number): number {
  if (windowSeconds <= 30 * 60)        return 10;   // ≤ 30 min → 10 s buckets
  if (windowSeconds <= 2 * 60 * 60)    return 60;   // ≤ 2 h  → 1 min
  if (windowSeconds <= 12 * 60 * 60)   return 300;  // ≤ 12 h → 5 min
  if (windowSeconds <= 48 * 60 * 60)   return 900;  // ≤ 48 h → 15 min
  return 3600;                                      // longer → 1 h
}

// ── Panel component ────────────────────────────────────────────────────

interface PanelProps {
  title: string;
  subtitle?: string;
  metric: string;
  statistic?: string;
  groupByTags?: string[];
  filterTags?: Record<string, string>;
  aggregation?: string;
  mode?: 'raw' | 'delta';
  yLabel?: string;
  asArea?: boolean;
  range: ServerMetricsRange;
  stepSeconds: number;
  formatValue?: (v: number) => string;
}

function Panel({
  title, subtitle, metric, statistic, groupByTags, filterTags,
  aggregation, mode = 'raw', yLabel, asArea = false,
  range, stepSeconds, formatValue,
}: PanelProps) {
  const { data, isLoading, isError, error } = useServerMetricsSeries(
    { metric, statistic, groupByTags, filterTags, aggregation, mode, stepSeconds },
    range,
  );

  return (
    <div className={`${chartCardStyles.chartCard} ${styles.compactCard}`}>
      <div className={styles.chartHeader}>
        <span className={styles.chartTitle}>{title}</span>
        {subtitle && <span className={styles.chartMeta}>{subtitle}</span>}
      </div>
      <PanelBody
        data={data}
        loading={isLoading}
        error={isError ? (error as Error | null)?.message ?? 'query failed' : null}
        yLabel={yLabel}
        asArea={asArea}
        formatValue={formatValue}
      />
    </div>
  );
}

function PanelBody({
  data, loading, error, yLabel, asArea, formatValue,
}: {
  data: ServerMetricQueryResponse | undefined;
  loading: boolean;
  error: string | null;
  yLabel?: string;
  asArea?: boolean;
  formatValue?: (v: number) => string;
}) {
  const points = useMemo(() => flatten(data?.series ?? []), [data]);

  if (loading) {
    return <div style={{ minHeight: 160, display: 'grid', placeItems: 'center' }}>
      <Spinner />
    </div>;
  }
  if (error) {
    return <EmptyState title="Query failed" description={error} />;
  }
  if (!data || data.series.length === 0 || points.rows.length === 0) {
    return <EmptyState title="No data" description="No samples in the selected window" />;
  }

  return (
    <ThemedChart data={points.rows} height={180} xDataKey="t" xTickFormatter={formatTime}
                 yLabel={yLabel} yTickFormatter={formatValue}>
      {points.seriesKeys.map((key, idx) => {
        const color = CHART_COLORS[idx % CHART_COLORS.length];
        return asArea ? (
          <Area key={key} dataKey={key} name={key} stroke={color} fill={color}
                fillOpacity={0.18} strokeWidth={2} dot={false} />
        ) : (
          <Line key={key} dataKey={key} name={key} stroke={color} strokeWidth={2} dot={false} />
        );
      })}
    </ThemedChart>
  );
}

/**
 * Turn ServerMetricSeries[] into a single array of rows keyed by series label.
 * Multiple series become overlapping lines on the same time axis; buckets are
 * merged on `t` so Recharts can render them as one dataset.
 */
function flatten(series: ServerMetricSeries[]): { rows: Array<Record<string, number | string>>; seriesKeys: string[] } {
  if (series.length === 0) return { rows: [], seriesKeys: [] };

  const seriesKeys = series.map(seriesLabel);
  const rowsByTime = new Map<string, Record<string, number | string>>();
  series.forEach((s, i) => {
    const key = seriesKeys[i];
    for (const p of s.points) {
      let row = rowsByTime.get(p.t);
      if (!row) {
        row = { t: p.t };
        rowsByTime.set(p.t, row);
      }
      row[key] = p.v;
    }
  });
  const rows = Array.from(rowsByTime.values()).sort((a, b) =>
    (a.t as string).localeCompare(b.t as string));
  return { rows, seriesKeys };
}

function seriesLabel(s: ServerMetricSeries): string {
  const entries = Object.entries(s.tags);
  if (entries.length === 0) return 'value';
  return entries.map(([k, v]) => `${k}=${v}`).join(' · ');
}

function formatTime(iso: string | number): string {
  const d = typeof iso === 'number' ? new Date(iso) : new Date(String(iso));
  return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
}

function formatMB(bytes: number): string {
  return `${(bytes / (1024 * 1024)).toFixed(0)} MB`;
}

function formatPct(frac: number): string {
  return `${(frac * 100).toFixed(0)}%`;
}

// ── Page ───────────────────────────────────────────────────────────────

export default function ServerMetricsAdminPage() {
  // Drive the entire page from the global time-range control in the TopBar.
  const { timeRange } = useGlobalFilters();
  const range: ServerMetricsRange = useMemo(
    () => ({ from: timeRange.start, to: timeRange.end }),
    [timeRange.start, timeRange.end],
  );
  const windowSeconds = Math.max(
    1,
    Math.round((range.to.getTime() - range.from.getTime()) / 1000),
  );
  const stepSeconds = stepSecondsFor(windowSeconds);

  const { data: catalog } = useServerMetricsCatalog(range);
  const { data: instances } = useServerMetricsInstances(range);

  const has = (metricName: string) =>
    (catalog ?? []).some((c) => c.metricName === metricName);

  return (
    <div className={styles.page}>
      {/* Toolbar — just server-instance badges. Time range is driven by
          the global time-range control in the TopBar. */}
      <div className={styles.toolbar}>
        <div className={styles.instanceStrip}>
          {(instances ?? []).slice(0, 8).map((i) => (
            <Badge key={i.serverInstanceId} label={i.serverInstanceId} variant="outlined" />
          ))}
          {(instances ?? []).length > 8 && (
            <Badge label={`+${(instances ?? []).length - 8}`} variant="outlined" />
          )}
          {(instances ?? []).length === 0 && (
            <Badge label="no samples in window" variant="outlined" />
          )}
        </div>
      </div>

      {/* Row 1: Server health */}
      <section>
        <div className={styles.sectionTitle}>
          Server health
          <span className={styles.sectionSubtitle}>agents, ingestion, auth</span>
        </div>
        <div className={styles.row}>
          <Panel
            title="Agents by state"
            subtitle="stacked area"
            metric="cameleer.agents.connected"
            statistic="value"
            groupByTags={['state']}
            aggregation="avg"
            asArea
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="Ingestion buffer depth"
            subtitle="by type"
            metric="cameleer.ingestion.buffer.size"
            statistic="value"
            groupByTags={['type']}
            aggregation="avg"
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
        <div className={styles.row} style={{ marginTop: 14 }}>
          <Panel
            title="Ingestion drops / interval"
            subtitle="per-bucket delta"
            metric="cameleer.ingestion.drops"
            statistic="count"
            groupByTags={['reason']}
            mode="delta"
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="Auth failures / interval"
            subtitle="per-bucket delta"
            metric="cameleer.auth.failures"
            statistic="count"
            groupByTags={['reason']}
            mode="delta"
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
      </section>

      {/* Row 2: JVM */}
      <section>
        <div className={styles.sectionTitle}>
          JVM
          <span className={styles.sectionSubtitle}>memory, CPU, threads, GC</span>
        </div>
        <div className={styles.rowTriple}>
          <Panel
            title="Heap used"
            subtitle="sum across pools"
            metric="jvm.memory.used"
            statistic="value"
            filterTags={{ area: 'heap' }}
            aggregation="sum"
            asArea
            yLabel="MB"
            formatValue={formatMB}
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="CPU usage"
            subtitle="process + system"
            metric="process.cpu.usage"
            statistic="value"
            aggregation="avg"
            asArea
            yLabel="%"
            formatValue={formatPct}
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="GC pause max"
            subtitle="by cause"
            metric="jvm.gc.pause"
            statistic="max"
            groupByTags={['cause']}
            aggregation="max"
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
        <div className={styles.row} style={{ marginTop: 14 }}>
          <Panel
            title="Thread count"
            subtitle="live threads"
            metric="jvm.threads.live"
            statistic="value"
            aggregation="avg"
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="Heap committed vs max"
            subtitle="sum across pools"
            metric="jvm.memory.committed"
            statistic="value"
            filterTags={{ area: 'heap' }}
            aggregation="sum"
            yLabel="MB"
            formatValue={formatMB}
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
      </section>

      {/* Row 3: HTTP + DB */}
      <section>
        <div className={styles.sectionTitle}>
          HTTP &amp; DB pools
          <span className={styles.sectionSubtitle}>requests, Hikari saturation</span>
        </div>
        <div className={styles.rowTriple}>
          <Panel
            title="HTTP latency — mean by URI"
            subtitle="SUCCESS only"
            metric="http.server.requests"
            statistic="mean"
            groupByTags={['uri']}
            filterTags={{ outcome: 'SUCCESS' }}
            aggregation="avg"
            yLabel="s"
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="HTTP requests / interval"
            subtitle="all outcomes"
            metric="http.server.requests"
            statistic="count"
            mode="delta"
            aggregation="sum"
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="Hikari pool — active vs pending"
            subtitle="by pool"
            metric="hikaricp.connections.active"
            statistic="value"
            groupByTags={['pool']}
            aggregation="avg"
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
        <div className={styles.row} style={{ marginTop: 14 }}>
          <Panel
            title="Hikari acquire timeouts"
            subtitle="per-bucket delta"
            metric="hikaricp.connections.timeout"
            statistic="count"
            groupByTags={['pool']}
            mode="delta"
            range={range}
            stepSeconds={stepSeconds}
          />
          <Panel
            title="Log events by level"
            subtitle="per-bucket delta"
            metric="logback.events"
            statistic="count"
            groupByTags={['level']}
            mode="delta"
            range={range}
            stepSeconds={stepSeconds}
          />
        </div>
      </section>

      {/* Row 4: Alerting */}
      {(has('alerting_instances_total')
        || has('alerting_eval_errors_total')
        || has('alerting_webhook_delivery_duration_seconds')) && (
        <section>
          <div className={styles.sectionTitle}>
            Alerting
            <span className={styles.sectionSubtitle}>instances, eval errors, webhook delivery</span>
          </div>
          <div className={styles.rowTriple}>
            {has('alerting_instances_total') && (
              <Panel
                title="Alert instances by state"
                subtitle="stacked"
                metric="alerting_instances_total"
                statistic="value"
                groupByTags={['state']}
                aggregation="avg"
                asArea
                range={range}
                stepSeconds={stepSeconds}
              />
            )}
            {has('alerting_eval_errors_total') && (
              <Panel
                title="Eval errors / interval"
                subtitle="by kind"
                metric="alerting_eval_errors_total"
                statistic="count"
                groupByTags={['kind']}
                mode="delta"
                range={range}
                stepSeconds={stepSeconds}
              />
            )}
            {has('alerting_webhook_delivery_duration_seconds') && (
              <Panel
                title="Webhook delivery max"
                subtitle="max latency per bucket"
                metric="alerting_webhook_delivery_duration_seconds"
                statistic="max"
                aggregation="max"
                yLabel="s"
                range={range}
                stepSeconds={stepSeconds}
              />
            )}
          </div>
        </section>
      )}

      {/* Row 5: Deployments (only when runtime orchestration is enabled) */}
      {(has('cameleer.deployments.outcome') || has('cameleer.deployments.duration')) && (
        <section>
          <div className={styles.sectionTitle}>
            Deployments
            <span className={styles.sectionSubtitle}>outcomes, duration</span>
          </div>
          <div className={styles.row}>
            {has('cameleer.deployments.outcome') && (
              <Panel
                title="Deploy outcomes / interval"
                subtitle="by status"
                metric="cameleer.deployments.outcome"
                statistic="count"
                groupByTags={['status']}
                mode="delta"
                range={range}
                stepSeconds={stepSeconds}
              />
            )}
            {has('cameleer.deployments.duration') && (
              <Panel
                title="Deploy duration mean"
                subtitle="total_time / count"
                metric="cameleer.deployments.duration"
                statistic="mean"
                aggregation="avg"
                yLabel="s"
                range={range}
                stepSeconds={stepSeconds}
              />
            )}
          </div>
        </section>
      )}
    </div>
  );
}
