import { memo, useMemo, useState, type CSSProperties } from "react";
import { RefreshButton } from "@/components/ui/Button";
import {
  CartesianGrid,
  Line,
  LineChart,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from "recharts";
import { buildTrendTooltipRows, formatTrendRegionLabel, formatUtc8Tick, REGION_COLORS, type TrendTooltipRow } from "../lib/chart";
import { formatUptime, formatUtc8Time } from "../lib/formatters";
import { QueryErrorBanner } from "../components/query-error-banner";
import { SectionLoadingCard } from "../components/section-loading-card";
import type { AcsResourceTrends, ResourceTrendMetricKey } from "@/lib/observe/trends";

const METRIC_LABELS: Record<ResourceTrendMetricKey, string> = {
  cpuRequestUsage: "CPU Request Usage",
  cpuLimitUsage: "CPU Limit Usage",
  memoryRequestUsage: "Memory Request Usage",
  memoryLimitUsage: "Memory Limit Usage",
  uptimeSeconds: "Process Uptime",
};

const TREND_CHART_HEIGHT = 256;

export const TREND_TOOLTIP_WRAPPER_STYLE: CSSProperties = {
  zIndex: 20,
  pointerEvents: "none",
};

export const TREND_TOOLTIP_LIST_CLASS =
  "px-3 py-2 space-y-1.5 text-sm max-h-[calc(100vh-12rem)] overflow-y-auto overscroll-contain";

type LegendPayload = {
  dataKey?: unknown;
};

function pluralizeRegion(count: number): string {
  return count === 1 ? "region" : "regions";
}

export const TrendsSection = memo(function TrendsSection({
  trends,
  trendsLoading,
  trendsError,
  rangeMinutes,
  setRangeMinutes,
  onRefresh,
  xAxisTicksBuilder,
}: {
  trends: AcsResourceTrends | null;
  trendsLoading: boolean;
  trendsError?: string;
  rangeMinutes: number;
  setRangeMinutes: (value: number) => void;
  onRefresh: () => void;
  xAxisTicksBuilder: (startIso: string, endIso: string) => number[];
}) {
  const trendMetrics = useMemo(
    () => trends?.metrics.filter((metric) => metric.metricKey !== "uptimeSeconds") ?? [],
    [trends]
  );
  const readyRegions = useMemo(
    () => trends?.regions.filter((region) => region.status === "ready") ?? [],
    [trends]
  );
  const xAxisTicks = useMemo(
    () => (trends ? xAxisTicksBuilder(trends.range.start, trends.range.end) : []),
    [trends, xAxisTicksBuilder]
  );

  return (
    <section data-testid="trends-section" className="space-y-4">
      <div className="flex items-center justify-between gap-4">
        <div>
          <h3 className="text-lg font-semibold">Resource Trends</h3>
          <p className="text-sm text-text-secondary mt-1">Resource usage on the same time range.</p>
        </div>
        <div className="flex items-end gap-3">
          <label className="grid gap-1 text-xs uppercase tracking-wider text-text-muted">
            Range
            <select
              aria-label="Time range"
              value={rangeMinutes}
              onChange={(event) => setRangeMinutes(Number(event.target.value))}
              className="h-8 px-2.5 rounded-md bg-surface-0 border border-surface-2 text-sm text-text-primary normal-case tracking-normal"
            >
              <option value={60}>1h</option>
              <option value={120}>2h</option>
              <option value={360}>6h</option>
              <option value={1440}>24h</option>
              <option value={4320}>3d</option>
              <option value={10080}>7d</option>
            </select>
          </label>
          <RefreshButton
            aria-label="Refresh Trends"
            onClick={onRefresh}
            disabled={trendsLoading}
            busy={trendsLoading}
          />
        </div>
      </div>

      <QueryErrorBanner title="Failed to load Trends" message={trendsError ?? ""} />

      {!trends && trendsLoading ? (
        <SectionLoadingCard
          label="Loading Trends"
          testId="trends-loading"
        />
      ) : null}

      {trends && (
        <>
          <TrendsQueryErrorPrompt trends={trends} />
          <div className="grid grid-cols-1 xl:grid-cols-2 gap-4">
            {trendMetrics.map((metric) => (
              <TrendChart
                key={metric.metricKey}
                metric={metric}
                regions={readyRegions}
                xAxisTicks={xAxisTicks}
              />
            ))}
          </div>
        </>
      )}
    </section>
  );
});

function TrendsQueryErrorPrompt({ trends }: { trends: AcsResourceTrends }) {
  const queryErrorRegions = trends.regions.filter((region) => region.status === "query-error");
  if (queryErrorRegions.length === 0) return null;

  return (
    <div className="rounded-lg border border-danger/20 bg-danger-muted px-4 py-3 text-sm text-danger">
      <div className="font-medium">
        VictoriaMetrics query failed for {queryErrorRegions.length} {pluralizeRegion(queryErrorRegions.length)}.
      </div>
      <div className="mt-1 space-y-1 text-xs">
        {queryErrorRegions.map((region) => (
          <div key={region.regionId}>
            {region.regionName}: {region.errorMessage ?? "VictoriaMetrics query failed"}
          </div>
        ))}
      </div>
    </div>
  );
}

const TrendChart = memo(function TrendChart({
  metric,
  regions,
  xAxisTicks,
}: {
  metric: AcsResourceTrends["metrics"][number];
  regions: AcsResourceTrends["regions"];
  xAxisTicks: number[];
}) {
  const [focusedSeries, setFocusedSeries] = useState<string | null>(null);
  const isUptime = metric.metricKey === "uptimeSeconds";
  const data = useMemo(
    () =>
      metric.points.map((point) => ({
        timestamp: point.timestamp,
        ...Object.fromEntries(
          Object.entries(point.values).map(([regionId, value]) => [
            regionId,
            value === null ? null : isUptime ? value : Number((value * 100).toFixed(2)),
          ])
        ),
      })),
    [isUptime, metric.points]
  );
  const handleLegendClick = (entry: LegendPayload) => {
    if (typeof entry.dataKey !== "string") return;
    const dataKey = entry.dataKey;
    setFocusedSeries((current) => (current === dataKey ? null : dataKey));
  };

  const isSeriesVisible = (regionId: string): boolean =>
    focusedSeries === null || focusedSeries === regionId;
  const regionLabelById = useMemo(
    () => new Map(regions.map((region) => [region.regionId, formatTrendRegionLabel(region)])),
    [regions]
  );

  return (
    <div className="bg-surface-0 border border-surface-2 rounded-lg p-4">
      <h4 className="text-sm font-semibold">{METRIC_LABELS[metric.metricKey]}</h4>
      <div className="mt-3 min-w-0">
        <ResponsiveContainer width="100%" height={TREND_CHART_HEIGHT}>
          <LineChart data={data} margin={{ top: 8, right: 16, bottom: 8, left: 0 }}>
            <CartesianGrid stroke="var(--surface-2)" strokeDasharray="3 3" />
            <XAxis
              dataKey="timestamp"
              tick={{ fill: "var(--text-muted)", fontSize: 12 }}
              tickFormatter={(value) => formatUtc8Tick(Number(value))}
              type="number"
              domain={["dataMin", "dataMax"]}
              ticks={xAxisTicks}
            />
            <YAxis
              tick={{ fill: "var(--text-muted)", fontSize: 12 }}
              tickFormatter={(value) =>
                isUptime ? formatUptime(Number(value)) : `${Number(value).toFixed(0)}%`
              }
            />
            <Tooltip
              allowEscapeViewBox={{ x: false, y: true }}
              reverseDirection={{ x: false, y: true }}
              wrapperStyle={TREND_TOOLTIP_WRAPPER_STYLE}
              content={({ active, label, payload }) => {
                if (!active || !Array.isArray(payload) || payload.length === 0) return null;

                const rows = payload.flatMap((entry): TrendTooltipRow[] => {
                  const id = typeof entry.dataKey === "string" ? entry.dataKey : null;
                  const fallbackName = typeof entry.name === "string" ? entry.name : null;
                  const name = id ? (regionLabelById.get(id) ?? fallbackName) : fallbackName;
                  const value = typeof entry.value === "number" ? entry.value : null;
                  if (!id || !name || value === null) return [];
                  return [
                    {
                      id,
                      name,
                      value,
                      color: typeof entry.color === "string" ? entry.color : undefined,
                    },
                  ];
                });
                const visibleRows = buildTrendTooltipRows(rows);

                return (
                  <div className="max-w-[20rem] rounded-md border border-surface-2 bg-surface-0 shadow-sm">
                    <div className="px-3 py-2 text-xs font-mono text-text-secondary border-b border-surface-2">
                      {formatUtc8Time(new Date(Number(label) * 1000).toISOString())}
                    </div>
                    <ul className={TREND_TOOLTIP_LIST_CLASS}>
                      {visibleRows.map((row) => (
                        <li key={row.id} className="flex items-center justify-between gap-4">
                          <span className="inline-flex items-center gap-2 text-text-primary min-w-0">
                            <span
                              className="inline-block h-2 w-2 rounded-full shrink-0"
                              style={{ backgroundColor: row.color ?? "var(--text-muted)" }}
                            />
                            <span className="truncate">{row.name}</span>
                          </span>
                          <span className="font-mono text-text-secondary shrink-0">
                            {isUptime ? formatUptime(row.value) : `${row.value.toFixed(2)}%`}
                          </span>
                        </li>
                      ))}
                    </ul>
                  </div>
                );
              }}
            />
            {regions.map((region, index) => (
              <Line
                key={region.regionId}
                type="monotone"
                dataKey={region.regionId}
                name={formatTrendRegionLabel(region)}
                stroke={REGION_COLORS[index % REGION_COLORS.length]}
                dot={false}
                hide={!isSeriesVisible(region.regionId)}
                connectNulls={false}
              />
            ))}
          </LineChart>
        </ResponsiveContainer>
      </div>
      <div className="mt-3 max-h-24 overflow-y-auto pr-1">
        <div className="flex flex-wrap gap-2">
          {regions.map((region, index) => {
            const active = isSeriesVisible(region.regionId);
            return (
              <button
                key={region.regionId}
                type="button"
                aria-pressed={active}
                onClick={() => handleLegendClick({ dataKey: region.regionId })}
                className={`inline-flex items-center gap-2 rounded-md border px-2 py-1 text-xs transition-colors ${
                  active
                    ? "border-surface-2 bg-surface-1 text-text-primary"
                    : "border-surface-2/60 bg-surface-0 text-text-muted"
                }`}
              >
                <span
                  className="inline-block h-2 w-2 rounded-full"
                  style={{ backgroundColor: REGION_COLORS[index % REGION_COLORS.length] }}
                />
                {formatTrendRegionLabel(region)}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
});
