"use client";

import { useId, useMemo, useState } from "react";
import { cn } from "@/lib/cn";
import {
  chartableFollowerPoints,
  formatChartAxisDate,
  formatChartTooltipDate,
  formatNullableMetric,
} from "@/lib/historical-analytics";
import type { HistoricalSeriesPoint } from "@/types/social-analytics-history";

type ChartPoint = { captured_at: string; value: number };

const WIDTH = 640;
const HEIGHT = 220;
const PAD = { top: 16, right: 16, bottom: 36, left: 52 };

export function FollowerTrendChart({
  points,
  className,
  platformLabel,
}: {
  points: HistoricalSeriesPoint[];
  className?: string;
  /** Optional platform name for accessible chart summaries. */
  platformLabel?: string;
}) {
  const gradientId = useId().replace(/:/g, "");
  const [activeIndex, setActiveIndex] = useState<number | null>(null);

  const chartPoints = useMemo(() => chartableFollowerPoints(points), [points]);

  if (chartPoints.length === 0) {
    return (
      <div
        className={cn(
          "flex h-[220px] items-center justify-center rounded-pv border border-dashed border-line bg-bg px-4 text-center",
          className,
        )}
        role="img"
        aria-label={
          platformLabel
            ? `No ${platformLabel} follower observations in this period`
            : "No follower observations in this period"
        }
      >
        <p className="text-[0.8125rem] text-ink-60">
          No follower observations in this period yet.
        </p>
      </div>
    );
  }

  if (chartPoints.length === 1) {
    const only = chartPoints[0];
    return (
      <div
        className={cn(
          "flex h-[220px] flex-col items-center justify-center gap-2 rounded-pv border border-line bg-bg px-4 text-center",
          className,
        )}
        role="img"
        aria-label={`${platformLabel ? `${platformLabel} · ` : ""}Single follower observation: ${formatNullableMetric(only.value)} on ${formatChartTooltipDate(only.captured_at)}`}
      >
        <p className="text-[1.25rem] font-semibold tabular-nums text-primary">
          {formatNullableMetric(only.value)}
        </p>
        <p className="text-[0.8125rem] text-ink-60">
          Single observation · {formatChartTooltipDate(only.captured_at)}
        </p>
        <p className="max-w-[36ch] text-[0.75rem] text-ink-40">
          Sparse history is shown as captured — not interpolated into a daily series.
        </p>
      </div>
    );
  }

  const plotWidth = WIDTH - PAD.left - PAD.right;
  const plotHeight = HEIGHT - PAD.top - PAD.bottom;
  const values = chartPoints.map((point) => point.value);
  const minValue = Math.min(...values);
  const maxValue = Math.max(...values);
  const span = Math.max(maxValue - minValue, 1);
  const yPad = span * 0.08;
  const yMin = Math.max(0, minValue - yPad);
  const yMax = maxValue + yPad;
  const ySpan = Math.max(yMax - yMin, 1);

  const times = chartPoints.map((point) => new Date(point.captured_at).getTime());
  const tMin = Math.min(...times);
  const tMax = Math.max(...times);
  const tSpan = Math.max(tMax - tMin, 1);

  const coords = chartPoints.map((point) => {
    const t = new Date(point.captured_at).getTime();
    const x = PAD.left + ((t - tMin) / tSpan) * plotWidth;
    const y = PAD.top + (1 - (point.value - yMin) / ySpan) * plotHeight;
    return { x, y, point };
  });

  const linePath = coords
    .map((coord, index) => `${index === 0 ? "M" : "L"} ${coord.x.toFixed(2)} ${coord.y.toFixed(2)}`)
    .join(" ");

  const areaPath = `${linePath} L ${coords[coords.length - 1].x.toFixed(2)} ${(PAD.top + plotHeight).toFixed(2)} L ${coords[0].x.toFixed(2)} ${(PAD.top + plotHeight).toFixed(2)} Z`;

  const yTicks = [yMin, yMin + ySpan / 2, yMax];
  const xTickIndexes =
    chartPoints.length <= 3
      ? chartPoints.map((_, index) => index)
      : [0, Math.floor((chartPoints.length - 1) / 2), chartPoints.length - 1];

  const active = activeIndex !== null ? coords[activeIndex] : null;
  const summary = buildAccessibleSummary(chartPoints, platformLabel);

  return (
    <div className={cn("relative overflow-hidden rounded-pv border border-line bg-bg", className)}>
      <svg
        viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
        className="h-auto w-full"
        role="img"
        aria-label={summary}
        onMouseLeave={() => setActiveIndex(null)}
      >
        <defs>
          <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#172554" stopOpacity="0.18" />
            <stop offset="100%" stopColor="#172554" stopOpacity="0" />
          </linearGradient>
        </defs>

        {yTicks.map((tick, index) => {
          const y = PAD.top + (1 - (tick - yMin) / ySpan) * plotHeight;
          return (
            <g key={`y-${index}`}>
              <line
                x1={PAD.left}
                x2={WIDTH - PAD.right}
                y1={y}
                y2={y}
                stroke="currentColor"
                className="text-line"
                strokeWidth="1"
              />
              <text
                x={PAD.left - 8}
                y={y + 3}
                textAnchor="end"
                className="fill-ink-40 text-[10px]"
              >
                {formatNullableMetric(Math.round(tick))}
              </text>
            </g>
          );
        })}

        <path d={areaPath} fill={`url(#${gradientId})`} opacity="0.55" />
        <path
          d={linePath}
          fill="none"
          stroke="#172554"
          strokeWidth="2"
          strokeLinejoin="round"
          strokeLinecap="round"
        />

        {coords.map((coord, index) => (
          <circle
            key={coord.point.captured_at}
            cx={coord.x}
            cy={coord.y}
            r={activeIndex === index ? 5.5 : 4}
            fill="#172554"
            stroke="#ffffff"
            strokeWidth="2"
            onMouseEnter={() => setActiveIndex(index)}
            onFocus={() => setActiveIndex(index)}
            tabIndex={0}
            role="listitem"
            aria-label={`${formatChartTooltipDate(coord.point.captured_at)}: ${formatNullableMetric(coord.point.value)} followers`}
          />
        ))}

        {xTickIndexes.map((index) => {
          const coord = coords[index];
          return (
            <text
              key={`x-${index}`}
              x={coord.x}
              y={HEIGHT - 12}
              textAnchor="middle"
              className="fill-ink-40 text-[10px]"
            >
              {formatChartAxisDate(coord.point.captured_at)}
            </text>
          );
        })}

        {active ? (
          <line
            x1={active.x}
            x2={active.x}
            y1={PAD.top}
            y2={PAD.top + plotHeight}
            stroke="#F97316"
            strokeDasharray="4 4"
            strokeWidth="1"
          />
        ) : null}
      </svg>

      {active ? (
        <div
          className="pointer-events-none absolute left-1/2 top-3 z-10 -translate-x-1/2 rounded-pv border border-line bg-surface px-2.5 py-1.5 shadow-pv"
          role="tooltip"
        >
          <p className="text-[0.6875rem] text-ink-40">
            {formatChartTooltipDate(active.point.captured_at)}
          </p>
          <p className="text-[0.8125rem] font-semibold tabular-nums text-primary">
            {formatNullableMetric(active.point.value)} followers
          </p>
        </div>
      ) : null}

      <p className="border-t border-line px-3 py-2 text-[0.75rem] text-ink-40">
        {chartPoints.length} observations · points placed by capture time (not daily interpolated)
      </p>
    </div>
  );
}

function buildAccessibleSummary(points: ChartPoint[], platformLabel?: string): string {
  const first = points[0];
  const last = points[points.length - 1];
  const prefix = platformLabel ? `${platformLabel} follower trend` : "Follower trend";
  return `${prefix} with ${points.length} observations from ${formatChartTooltipDate(first.captured_at)} to ${formatChartTooltipDate(last.captured_at)}. Latest value ${formatNullableMetric(last.value)}.`;
}
