import { useMemo } from 'react';
import { useNavigate } from 'react-router';
import {
  KpiStrip,
  DataTable,
  ThemedChart,
  Area,
  Line,
  CHART_COLORS,
  Card,
  Sparkline,
  MonoText,
  StatusDot,
  Badge,
} from '@cameleer/design-system';
import type { KpiItem, Column } from '@cameleer/design-system';
import { useGlobalFilters } from '@cameleer/design-system';
import { useRouteMetrics } from '../../api/queries/catalog';
import { useExecutionStats, useStatsTimeseries } from '../../api/queries/executions';
import { useTimeseriesByApp, useTopErrors, useAllAppSettings, usePunchcard } from '../../api/queries/dashboard';
import { useEnvironmentStore } from '../../api/environment-store';
import type { AppSettings } from '../../api/queries/dashboard';
import { Treemap } from './Treemap';
import type { TreemapItem } from './Treemap';
import { PunchcardHeatmap } from './PunchcardHeatmap';
import type { RouteMetrics } from '../../api/types';
import {
  computeHealthDot,
  formatThroughput,
  formatSlaCompliance,
  trendIndicator,
  type HealthStatus,
} from './dashboard-utils';
import styles from './DashboardTab.module.css';
import tableStyles from '../../styles/table-section.module.css';
import refreshStyles from '../../styles/refresh-indicator.module.css';
import rateStyles from '../../styles/rate-colors.module.css';

// ── Row type for application health table ───────────────────────────────────

interface AppRow {
  id: string;
  appId: string;
  health: HealthStatus;
  throughput: number;
  throughputLabel: string;
  successRate: number;
  p99DurationMs: number;
  slaCompliance: number;
  errorCount: number;
  sparkline: number[];
}

// ── Table columns ───────────────────────────────────────────────────────────

const APP_COLUMNS: Column<AppRow>[] = [
  {
    key: 'health',
    header: '',
    render: (_, row) => <StatusDot variant={row.health} />,
  },
  {
    key: 'appId',
    header: 'Application',
    sortable: true,
    render: (_, row) => (
      <span className={styles.appNameCell}>{row.appId}</span>
    ),
  },
  {
    key: 'throughput',
    header: 'Throughput',
    sortable: true,
    render: (_, row) => (
      <MonoText size="sm">{row.throughputLabel}</MonoText>
    ),
  },
  {
    key: 'successRate',
    header: 'Success %',
    sortable: true,
    render: (_, row) => {
      const pct = row.successRate;
      const cls = pct >= 99 ? rateStyles.rateGood : pct >= 97 ? rateStyles.rateWarn : rateStyles.rateBad;
      return <MonoText size="sm" className={cls}>{pct.toFixed(1)}%</MonoText>;
    },
  },
  {
    key: 'p99DurationMs',
    header: 'P99',
    sortable: true,
    render: (_, row) => {
      const cls = row.p99DurationMs > 300 ? rateStyles.rateBad : row.p99DurationMs > 200 ? rateStyles.rateWarn : rateStyles.rateGood;
      return <MonoText size="sm" className={cls}>{Math.round(row.p99DurationMs)}ms</MonoText>;
    },
  },
  {
    key: 'slaCompliance',
    header: 'SLA %',
    sortable: true,
    render: (_, row) => {
      const cls = row.slaCompliance >= 99 ? rateStyles.rateGood : row.slaCompliance >= 95 ? rateStyles.rateWarn : rateStyles.rateBad;
      return <MonoText size="sm" className={cls}>{formatSlaCompliance(row.slaCompliance)}</MonoText>;
    },
  },
  {
    key: 'errorCount',
    header: 'Errors',
    sortable: true,
    render: (_, row) => {
      const cls = row.errorCount > 10 ? rateStyles.rateBad : row.errorCount > 0 ? rateStyles.rateWarn : rateStyles.rateGood;
      return <MonoText size="sm" className={cls}>{row.errorCount.toLocaleString()}</MonoText>;
    },
  },
  {
    key: 'sparkline',
    header: 'Trend',
    render: (_, row) => (
      <Sparkline data={row.sparkline} width={80} height={24} />
    ),
  },
];

// ── Aggregate RouteMetrics by appId ─────────────────────────────────────────

function aggregateByApp(
  metrics: RouteMetrics[],
  windowSeconds: number,
  settingsMap: Map<string, AppSettings>,
): AppRow[] {
  const grouped = new Map<string, RouteMetrics[]>();
  for (const m of metrics) {
    const list = grouped.get(m.appId) ?? [];
    list.push(m);
    grouped.set(m.appId, list);
  }

  const rows: AppRow[] = [];
  for (const [appId, routes] of grouped) {
    const totalExchanges = routes.reduce((s, r) => s + r.exchangeCount, 0);
    const totalFailed = routes.reduce((s, r) => s + r.exchangeCount * r.errorRate, 0);
    const successRate = totalExchanges > 0 ? ((totalExchanges - totalFailed) / totalExchanges) * 100 : 100;
    const errorRate = totalExchanges > 0 ? totalFailed / totalExchanges : 0;

    // Weighted average p99 by exchange count
    const p99Sum = routes.reduce((s, r) => s + r.p99DurationMs * r.exchangeCount, 0);
    const p99DurationMs = totalExchanges > 0 ? p99Sum / totalExchanges : 0;

    // SLA compliance: weighted average of per-route slaCompliance from backend
    const appSettings = settingsMap.get(appId);
    const slaWeightedSum = routes.reduce((s, r) => s + (r.slaCompliance ?? 100) * r.exchangeCount, 0);
    const slaCompliance = totalExchanges > 0 ? slaWeightedSum / totalExchanges : 100;

    const errorCount = Math.round(totalFailed);

    // Merge sparklines: sum across routes per bucket position
    const maxLen = Math.max(...routes.map((r) => (r.sparkline ?? []).length), 0);
    const sparkline: number[] = [];
    for (let i = 0; i < maxLen; i++) {
      sparkline.push(routes.reduce((s, r) => s + ((r.sparkline ?? [])[i] ?? 0), 0));
    }

    rows.push({
      id: appId,
      appId,
      health: computeHealthDot(errorRate, slaCompliance, appSettings),
      throughput: totalExchanges,
      throughputLabel: formatThroughput(totalExchanges, windowSeconds),
      successRate,
      p99DurationMs,
      slaCompliance,
      errorCount,
      sparkline,
    });
  }

  return rows.sort((a, b) => {
    const order: Record<HealthStatus, number> = { error: 0, warning: 1, success: 2 };
    return order[a.health] - order[b.health];
  });
}

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

function buildKpiItems(
  stats: {
    totalCount: number;
    failedCount: number;
    p99LatencyMs: number;
    prevTotalCount: number;
    prevFailedCount: number;
    prevP99LatencyMs: number;
  } | undefined,
  windowSeconds: number,
  slaCompliance: number,
  activeErrorCount: number,
  throughputSparkline: number[],
  successSparkline: number[],
  latencySparkline: number[],
  slaSparkline: number[],
  errorSparkline: number[],
): KpiItem[] {
  const totalCount = stats?.totalCount ?? 0;
  const failedCount = stats?.failedCount ?? 0;
  const prevTotalCount = stats?.prevTotalCount ?? 0;
  const prevFailedCount = stats?.prevFailedCount ?? 0;
  const p99Ms = stats?.p99LatencyMs ?? 0;
  const prevP99Ms = stats?.prevP99LatencyMs ?? 0;

  // Throughput
  const throughput = windowSeconds > 0 ? totalCount / windowSeconds : 0;
  const prevThroughput = windowSeconds > 0 ? prevTotalCount / windowSeconds : 0;
  const throughputTrend = trendIndicator(throughput, prevThroughput);

  // Success Rate
  const successPct = totalCount > 0 ? ((totalCount - failedCount) / totalCount) * 100 : 100;
  const prevSuccessPct = prevTotalCount > 0
    ? ((prevTotalCount - prevFailedCount) / prevTotalCount) * 100
    : 100;
  const successTrend = trendIndicator(successPct, prevSuccessPct);

  // P99 Latency
  const p99Trend = trendIndicator(p99Ms, prevP99Ms);

  // SLA compliance trend — higher is better, so invert the variant
  const slaTrend = trendIndicator(slaCompliance, 100);

  // Active Errors
  const prevErrorRate = prevTotalCount > 0 ? (prevFailedCount / prevTotalCount) * 100 : 0;
  const currentErrorRate = totalCount > 0 ? (failedCount / totalCount) * 100 : 0;
  const errorTrend = trendIndicator(currentErrorRate, prevErrorRate);

  return [
    {
      label: 'Throughput',
      value: formatThroughput(totalCount, windowSeconds),
      trend: {
        label: throughputTrend.label,
        variant: throughputTrend.direction === 'up' ? 'success' as const : throughputTrend.direction === 'down' ? 'error' as const : 'muted' as const,
      },
      subtitle: `${totalCount.toLocaleString()} msg total`,
      sparkline: throughputSparkline,
      borderColor: 'var(--amber)',
    },
    {
      label: 'Success Rate',
      value: `${successPct.toFixed(1)}%`,
      trend: {
        label: successTrend.label,
        variant: successPct >= 99 ? 'success' as const : successPct >= 97 ? 'warning' as const : 'error' as const,
      },
      subtitle: `${(totalCount - failedCount).toLocaleString()} succeeded`,
      sparkline: successSparkline,
      borderColor: successPct >= 99 ? 'var(--success)' : 'var(--error)',
    },
    {
      label: 'P99 Latency',
      value: `${Math.round(p99Ms)}ms`,
      trend: {
        label: p99Trend.label,
        variant: p99Ms > 300 ? 'error' as const : p99Ms > 200 ? 'warning' as const : 'success' as const,
      },
      subtitle: `prev ${Math.round(prevP99Ms)}ms`,
      sparkline: latencySparkline,
      borderColor: p99Ms > 300 ? 'var(--warning)' : 'var(--success)',
    },
    {
      label: 'SLA Compliance',
      value: formatSlaCompliance(slaCompliance),
      trend: {
        label: slaTrend.label,
        variant: slaCompliance >= 99 ? 'success' as const : slaCompliance >= 95 ? 'warning' as const : 'error' as const,
      },
      subtitle: 'P99 within threshold',
      sparkline: slaSparkline,
      borderColor: slaCompliance >= 99 ? 'var(--success)' : 'var(--warning)',
    },
    {
      label: 'Active Errors',
      value: String(activeErrorCount),
      trend: {
        label: errorTrend.label,
        variant: activeErrorCount === 0 ? 'success' as const : 'error' as const,
      },
      subtitle: `${failedCount.toLocaleString()} failures total`,
      sparkline: errorSparkline,
      borderColor: activeErrorCount === 0 ? 'var(--success)' : 'var(--error)',
    },
  ];
}

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

export default function DashboardL1() {
  const navigate = useNavigate();
  const selectedEnv = useEnvironmentStore((s) => s.environment);
  const { timeRange } = useGlobalFilters();
  const timeFrom = timeRange.start.toISOString();
  const timeTo = timeRange.end.toISOString();
  const windowSeconds = (timeRange.end.getTime() - timeRange.start.getTime()) / 1000;

  const { data: metrics } = useRouteMetrics(timeFrom, timeTo, undefined, selectedEnv);
  const { data: stats } = useExecutionStats(timeFrom, timeTo, undefined, undefined, selectedEnv);
  const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, undefined, undefined, selectedEnv);
  const { data: timeseriesByApp } = useTimeseriesByApp(timeFrom, timeTo, selectedEnv);
  const { data: topErrors } = useTopErrors(timeFrom, timeTo, undefined, undefined, selectedEnv);
  const { data: punchcardData } = usePunchcard(undefined, selectedEnv);
  const { data: allAppSettings } = useAllAppSettings(selectedEnv);

  // Build settings lookup map
  const settingsMap = useMemo(() => {
    const map = new Map<string, AppSettings>();
    for (const s of allAppSettings ?? []) {
      map.set(s.appId, s);
    }
    return map;
  }, [allAppSettings]);

  // Aggregate route metrics by appId for the table
  const appRows = useMemo(
    () => aggregateByApp(metrics ?? [], windowSeconds, settingsMap),
    [metrics, windowSeconds, settingsMap],
  );

  // Global SLA compliance from backend stats (exact calculation from executions table)
  const globalSlaCompliance = stats?.slaCompliance ?? -1;
  const effectiveSlaCompliance = globalSlaCompliance >= 0 ? globalSlaCompliance : 100;

  // Active error count = distinct error types
  const activeErrorCount = useMemo(
    () => (topErrors ?? []).length,
    [topErrors],
  );

  // KPI sparklines from timeseries buckets
  const throughputSparkline = useMemo(
    () => (timeseries?.buckets ?? []).map((b) => b.totalCount),
    [timeseries],
  );
  const successSparkline = useMemo(
    () => (timeseries?.buckets ?? []).map((b) =>
      b.totalCount > 0 ? ((b.totalCount - b.failedCount) / b.totalCount) * 100 : 100,
    ),
    [timeseries],
  );
  const latencySparkline = useMemo(
    () => (timeseries?.buckets ?? []).map((b) => b.p99DurationMs),
    [timeseries],
  );
  const slaSparkline = useMemo(
    () => (timeseries?.buckets ?? []).map((b) =>
      b.p99DurationMs <= 300 ? 100 : 0,
    ),
    [timeseries],
  );
  const errorSparkline = useMemo(
    () => (timeseries?.buckets ?? []).map((b) => b.failedCount),
    [timeseries],
  );

  const kpiItems = useMemo(
    () => buildKpiItems(
      stats,
      windowSeconds,
      effectiveSlaCompliance,
      activeErrorCount,
      throughputSparkline,
      successSparkline,
      latencySparkline,
      slaSparkline,
      errorSparkline,
    ),
    [stats, windowSeconds, effectiveSlaCompliance, activeErrorCount,
     throughputSparkline, successSparkline, latencySparkline, slaSparkline, errorSparkline],
  );

  // ── Per-app flat chart data (throughput stacked area) ───────────────────
  const throughputByAppData = useMemo(() => {
    if (!timeseriesByApp) return { data: [], keys: [] as string[] };
    const entries = Object.entries(timeseriesByApp);
    if (!entries.length) return { data: [], keys: [] as string[] };
    const len = entries[0][1].buckets.length;
    const keys = entries.map(([appId]) => appId);
    const data = Array.from({ length: len }, (_, i) => {
      const point: Record<string, number | string> = { idx: i };
      for (const [appId, { buckets }] of entries) {
        point[appId] = buckets[i]?.totalCount ?? 0;
      }
      return point;
    });
    return { data, keys };
  }, [timeseriesByApp]);

  // ── Per-app flat chart data (error rate line) ────────────────────────────
  const errorRateByAppData = useMemo(() => {
    if (!timeseriesByApp) return { data: [], keys: [] as string[] };
    const entries = Object.entries(timeseriesByApp);
    if (!entries.length) return { data: [], keys: [] as string[] };
    const len = entries[0][1].buckets.length;
    const keys = entries.map(([appId]) => appId);
    const data = Array.from({ length: len }, (_, i) => {
      const point: Record<string, number | string> = { idx: i };
      for (const [appId, { buckets }] of entries) {
        const b = buckets[i];
        point[appId] = b && b.totalCount > 0 ? (b.failedCount / b.totalCount) * 100 : 0;
      }
      return point;
    });
    return { data, keys };
  }, [timeseriesByApp]);

  // Treemap items: one per app, sized by exchange count, colored by SLA
  const treemapItems: TreemapItem[] = useMemo(
    () => appRows.map(r => ({ id: r.appId, label: r.appId, value: r.throughput, slaCompliance: r.slaCompliance })),
    [appRows],
  );

  return (
    <div className={styles.content}>
      <div className={refreshStyles.refreshIndicator}>
        <span className={refreshStyles.refreshDot} />
        <span className={refreshStyles.refreshText}>Auto-refresh: 30s</span>
      </div>

      {/* KPI header cards */}
      <KpiStrip items={kpiItems} />

      {/* Application Health table */}
      <div className={tableStyles.tableSection}>
        <div className={tableStyles.tableHeader}>
          <span className={tableStyles.tableTitle}>Application Health</span>
          <div className={tableStyles.tableRight}>
            <span className={tableStyles.tableMeta}>{appRows.length} applications</span>
            <Badge label="ALL" color="auto" />
          </div>
        </div>
        <DataTable
          columns={APP_COLUMNS}
          data={appRows}
          sortable
          onRowClick={(row) => navigate(`/dashboard/${row.appId}`)}
        />
      </div>

      {/* Side-by-side charts */}
      {throughputByAppData.data.length > 0 && (
        <div className={styles.chartGrid}>
          <Card title="Throughput by Application (msg/s)">
            <ThemedChart data={throughputByAppData.data} height={200} xDataKey="idx" yLabel="msg/s">
              {throughputByAppData.keys.map((key, i) => (
                <Area key={key} dataKey={key} name={key} stroke={CHART_COLORS[i % CHART_COLORS.length]}
                  fill={CHART_COLORS[i % CHART_COLORS.length]} fillOpacity={0.1} strokeWidth={2} dot={false} />
              ))}
            </ThemedChart>
          </Card>

          <Card title="Error Rate by Application (%)">
            <ThemedChart data={errorRateByAppData.data} height={200} xDataKey="idx" yLabel="%">
              {errorRateByAppData.keys.map((key, i) => (
                <Line key={key} dataKey={key} name={key} stroke={CHART_COLORS[i % CHART_COLORS.length]}
                  strokeWidth={2} dot={false} />
              ))}
            </ThemedChart>
          </Card>
        </div>
      )}

      {/* Treemap + Punchcard heatmaps side by side */}
      {treemapItems.length > 0 && (
        <div className={styles.vizRow}>
          <Card title="Application Volume vs SLA Compliance">
            <Treemap
              items={treemapItems}
              onItemClick={(id) => navigate(`/dashboard/${id}`)}
            />
          </Card>
          <Card title="7-Day Pattern">
            <PunchcardHeatmap cells={punchcardData ?? []} timeRangeMs={timeRange.end.getTime() - timeRange.start.getTime()} />
          </Card>
        </div>
      )}
    </div>
  );
}
