"use client";

import { useId, useMemo, useState } from "react";
import { motion } from "framer-motion";

export type RevenuePoint = { label: string; value: number };

type RevenueChartProps = {
  points: RevenuePoint[];
  maxValue: number;
  formatValue: (value: number) => string;
  height?: number;
};

/** Espaço reservado no topo para o pico não encostar na borda do traço. */
const TOP_INSET = 0.1;
const VIEW_W = 600;
const VIEW_H = 200;

/**
 * Interpolação cúbica monotônica (Fritsch–Carlson). Diferente de uma spline
 * comum, ela não gera "overshoot": entre dois dias sem receita a curva nunca
 * mergulha abaixo de zero, o que num gráfico de dinheiro seria mentira visual.
 */
function buildSmoothPath(ys: number[], xs: number[]) {
  const n = ys.length;
  if (n === 0) return "";
  if (n === 1) return `M ${xs[0]} ${ys[0]}`;

  const dx: number[] = [];
  const slope: number[] = [];
  for (let i = 0; i < n - 1; i++) {
    dx[i] = xs[i + 1] - xs[i];
    slope[i] = (ys[i + 1] - ys[i]) / dx[i];
  }

  const tangents: number[] = new Array(n);
  tangents[0] = slope[0];
  tangents[n - 1] = slope[n - 2];
  for (let i = 1; i < n - 1; i++) {
    tangents[i] = slope[i - 1] * slope[i] <= 0 ? 0 : (slope[i - 1] + slope[i]) / 2;
  }
  for (let i = 0; i < n - 1; i++) {
    if (slope[i] === 0) {
      tangents[i] = 0;
      tangents[i + 1] = 0;
    }
  }

  let d = `M ${xs[0]} ${ys[0]}`;
  for (let i = 0; i < n - 1; i++) {
    const c1x = xs[i] + dx[i] / 3;
    const c1y = ys[i] + (tangents[i] * dx[i]) / 3;
    const c2x = xs[i + 1] - dx[i] / 3;
    const c2y = ys[i + 1] - (tangents[i + 1] * dx[i]) / 3;
    d += ` C ${c1x} ${c1y} ${c2x} ${c2y} ${xs[i + 1]} ${ys[i + 1]}`;
  }
  return d;
}

export function RevenueChart({ points, maxValue, formatValue, height = 200 }: RevenueChartProps) {
  const gradientId = useId();
  const [activeIndex, setActiveIndex] = useState<number | null>(null);

  const geometry = useMemo(() => {
    const n = points.length;
    const safeMax = maxValue > 0 ? maxValue : 1;
    /** 0 = topo, 1 = base. */
    const ratio = (value: number) => 1 - (value / safeMax) * (1 - TOP_INSET);
    const xRatio = (index: number) => (n <= 1 ? 0.5 : index / (n - 1));

    const xs = points.map((_, index) => xRatio(index) * VIEW_W);
    const ys = points.map((point) => ratio(point.value) * VIEW_H);
    const line = buildSmoothPath(ys, xs);
    const area =
      n === 0
        ? ""
        : `${line} L ${xs[n - 1]} ${VIEW_H} L ${xs[0]} ${VIEW_H} Z`;

    let peakIndex = 0;
    points.forEach((point, index) => {
      if (point.value > points[peakIndex].value) peakIndex = index;
    });

    return { line, area, ratio, xRatio, peakIndex: n ? peakIndex : null };
  }, [points, maxValue]);

  if (points.length === 0) {
    return (
      <div
        className="flex items-center justify-center text-[13px] text-[var(--ks-color-text-muted)]"
        style={{ height }}
      >
        Sem dados para o período
      </div>
    );
  }

  const active = activeIndex !== null ? points[activeIndex] : null;
  const highlightIndex = activeIndex ?? geometry.peakIndex;
  const highlight = highlightIndex !== null ? points[highlightIndex] : null;

  const summary = `Receitas por dia, de ${points[0].label} a ${points[points.length - 1].label}. Máximo ${formatValue(maxValue)}.`;

  return (
    <div className="relative w-full select-none" style={{ height }}>
      <svg
        viewBox={`0 0 ${VIEW_W} ${VIEW_H}`}
        preserveAspectRatio="none"
        className="absolute inset-0 h-full w-full"
        role="img"
        aria-label={summary}
      >
        <defs>
          <linearGradient id={`${gradientId}-fill`} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--ks-brand-500)" stopOpacity="0.34" />
            <stop offset="55%" stopColor="var(--ks-brand-500)" stopOpacity="0.1" />
            <stop offset="100%" stopColor="var(--ks-brand-500)" stopOpacity="0" />
          </linearGradient>
          <linearGradient id={`${gradientId}-line`} x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="var(--ks-brand-600)" />
            <stop offset="55%" stopColor="var(--ks-teal)" />
            <stop offset="100%" stopColor="var(--ks-emerald)" />
          </linearGradient>
        </defs>

        {[0.1, 0.4, 0.7].map((line) => (
          <line
            key={line}
            x1="0"
            x2={VIEW_W}
            y1={line * VIEW_H}
            y2={line * VIEW_H}
            stroke="var(--ks-color-border-subtle)"
            strokeWidth="1"
            strokeDasharray="4 6"
            vectorEffect="non-scaling-stroke"
          />
        ))}

        <motion.path
          d={geometry.area}
          fill={`url(#${gradientId}-fill)`}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ duration: 0.6, delay: 0.25 }}
        />

        <motion.path
          d={geometry.line}
          fill="none"
          stroke={`url(#${gradientId}-line)`}
          strokeWidth="3"
          strokeLinecap="round"
          strokeLinejoin="round"
          vectorEffect="non-scaling-stroke"
          initial={{ pathLength: 0 }}
          animate={{ pathLength: 1 }}
          transition={{ duration: 0.9, ease: "easeOut" }}
        />

        {active ? (
          <line
            x1={geometry.xRatio(activeIndex!) * VIEW_W}
            x2={geometry.xRatio(activeIndex!) * VIEW_W}
            y1={geometry.ratio(active.value) * VIEW_H}
            y2={VIEW_H}
            stroke="var(--ks-brand-400)"
            strokeWidth="1.5"
            strokeDasharray="3 4"
            vectorEffect="non-scaling-stroke"
          />
        ) : null}
      </svg>

      {/* Marcador: seque o ponto sob o cursor ou, em repouso, o pico do período. */}
      {highlight && highlightIndex !== null ? (
        <span
          className="pointer-events-none absolute z-10 block h-3 w-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-[2.5px] border-[var(--ks-brand-600)] bg-[var(--ks-color-bg-elevated)] shadow-[0_0_0_4px_var(--ks-brand-50)] transition-[left,top] duration-200"
          style={{
            left: `${geometry.xRatio(highlightIndex) * 100}%`,
            top: `${geometry.ratio(highlight.value) * 100}%`,
          }}
        />
      ) : null}

      {active && activeIndex !== null ? (
        <div
          className="pointer-events-none absolute z-20 -translate-x-1/2 -translate-y-[calc(100%+14px)] whitespace-nowrap rounded-[var(--ks-radius-sm)] bg-[var(--ks-brand-800)] px-2.5 py-1.5 text-center shadow-[var(--ks-shadow-raised)]"
          style={{
            left: `${Math.min(Math.max(geometry.xRatio(activeIndex) * 100, 14), 86)}%`,
            top: `${geometry.ratio(active.value) * 100}%`,
          }}
        >
          <span className="block text-[13px] font-extrabold tabular-nums text-white">
            {formatValue(active.value)}
          </span>
          <span className="block text-[10px] font-semibold tabular-nums text-white/60">
            {active.label}
          </span>
        </div>
      ) : null}

      {/* Faixas de captura do cursor, uma por ponto. */}
      <div className="absolute inset-0 flex" onMouseLeave={() => setActiveIndex(null)}>
        {points.map((point, index) => (
          <button
            key={`${point.label}-${index}`}
            type="button"
            tabIndex={-1}
            aria-hidden="true"
            className="h-full flex-1 cursor-default"
            onMouseEnter={() => setActiveIndex(index)}
          />
        ))}
      </div>
    </div>
  );
}
