"use client";

import { motion } from "motion/react";
import { ChartFrame } from "./chart-frame";
import { linearScale, niceTicks } from "@/lib/chart-utils";
import { formatDelta } from "@/lib/format";

export type WaterfallStep = {
  label: string;
  value: number;
  /** "total" draws a full-height bar from zero; "delta" (default) is a floating change. */
  type?: "total" | "delta";
};

type WaterfallChartProps = {
  data: WaterfallStep[];
  width?: number;
  height?: number;
  className?: string;
};

const M = { top: 24, right: 18, bottom: 36, left: 48 };

/** WaterfallChart — floating bars rise/fall from the running total; dotted connectors draw between them. */
export function WaterfallChart({ data, width = 640, height = 380, className }: WaterfallChartProps) {
  const bars = data.reduce<Array<WaterfallStep & { start: number; end: number }>>((arr, d) => {
    const running = arr.length ? arr[arr.length - 1].end : 0;
    const start = d.type === "total" ? 0 : running;
    const end = d.type === "total" ? d.value : running + d.value;
    return [...arr, { ...d, start, end }];
  }, []);
  const lo = Math.min(0, ...bars.map((b) => Math.min(b.start, b.end)));
  const hi = Math.max(...bars.map((b) => Math.max(b.start, b.end)));
  const sy = linearScale([lo, hi], [height - M.bottom, M.top]);
  const ticks = niceTicks(lo, hi, 4);
  const plotW = width - M.left - M.right;
  const step = plotW / data.length;
  const bw = Math.min(step * 0.6, 64);

  return (
    <ChartFrame width={width} height={height} label="Gráfica de cascada" className={className}>
      {({ inView, reduce }) => (
        <>
          {ticks.map((t) => (
            <g key={t}>
              <line x1={M.left} x2={width - M.right} y1={sy(t)} y2={sy(t)} stroke="var(--ink-100)" />
              <text x={M.left - 8} y={sy(t)} textAnchor="end" dominantBaseline="middle" fontSize={11} fill="var(--ink-400)">{t}</text>
            </g>
          ))}
          {bars.map((b, i) => {
            const cx = M.left + step * (i + 0.5);
            const yTop = sy(Math.max(b.start, b.end));
            const yBot = sy(Math.min(b.start, b.end));
            const up = b.end >= b.start;
            const fill = b.type === "total" ? "var(--accent-600)" : up ? "var(--accent-500)" : "var(--ink-400)";
            const delay = 0.1 + i * 0.12;
            return (
              <g key={b.label}>
                <motion.rect
                  x={cx - bw / 2} y={yTop} width={bw} height={Math.max(yBot - yTop, 1)}
                  fill={fill}
                  initial={reduce ? false : { scaleY: 0 }}
                  animate={inView ? { scaleY: 1 } : { scaleY: 0 }}
                  transition={{ duration: 0.55, delay, ease: [0.77, 0, 0.175, 1] }}
                  style={{ transformOrigin: `${cx}px ${up ? yBot : yTop}px` }}
                />
                {i < bars.length - 1 && (
                  <motion.line
                    x1={cx + bw / 2} x2={M.left + step * (i + 1.5) - bw / 2}
                    y1={sy(b.end)} y2={sy(b.end)}
                    stroke="var(--ink-300)" strokeWidth={1.5} strokeDasharray="3 3"
                    initial={{ opacity: 0 }}
                    animate={inView ? { opacity: 1 } : { opacity: 0 }}
                    transition={{ duration: 0.3, delay: delay + 0.55 }}
                  />
                )}
                <text x={cx} y={height - M.bottom + 16} textAnchor="middle" fontSize={10} fill="var(--ink-500)">{b.label}</text>
                {b.type !== "total" && (
                  <text x={cx} y={yTop - 6} textAnchor="middle" fontSize={11} fontWeight={700} fill={up ? "var(--accent-700)" : "var(--ink-600)"}>
                    {formatDelta(b.value, 0, false)}
                  </text>
                )}
              </g>
            );
          })}
        </>
      )}
    </ChartFrame>
  );
}
