"use client";

import { motion } from "motion/react";
import { ChartFrame } from "@/components/charts/chart-frame";

export type FlowKind = "start" | "process" | "decision" | "end";
export type FlowNode = { id: string; label: string; kind?: FlowKind; col: number; row: number };
export type FlowEdge = { from: string; to: string; label?: string };

type FlowchartProps = {
  nodes: FlowNode[];
  edges: FlowEdge[];
  width?: number;
  height?: number;
  className?: string;
};

const BOX_W = 132;
const BOX_H = 50;

/** Flowchart — grid-placed nodes (start/process/decision/end shapes) reveal by row; connectors draw with arrowheads. */
export function Flowchart({ nodes, edges, width = 680, height = 420, className }: FlowchartProps) {
  const maxCol = Math.max(...nodes.map((n) => n.col));
  const maxRow = Math.max(...nodes.map((n) => n.row));
  const px = (c: number) => (maxCol === 0 ? width / 2 : 90 + (c / maxCol) * (width - 180));
  const py = (r: number) => (maxRow === 0 ? height / 2 : 50 + (r / maxRow) * (height - 100));
  const byId = new Map(nodes.map((n) => [n, { x: px(n.col), y: py(n.row) }] as const));
  const posOf = (id: string) => {
    const n = nodes.find((x) => x.id === id);
    return n ? byId.get(n)! : null;
  };

  return (
    <ChartFrame width={width} height={height} label="Diagrama de flujo" className={className}>
      {({ inView, reduce }) => (
        <>
          <defs>
            <marker id="sd-flow-arrow" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto">
              <path d="M0,0 L7,3 L0,6 Z" fill="var(--ink-400)" />
            </marker>
          </defs>
          {edges.map((e, i) => {
            const a = posOf(e.from);
            const b = posOf(e.to);
            if (!a || !b) return null;
            const vertical = Math.abs(b.y - a.y) >= Math.abs(b.x - a.x);
            const start = vertical ? { x: a.x, y: a.y + BOX_H / 2 } : { x: a.x + BOX_W / 2, y: a.y };
            const end = vertical ? { x: b.x, y: b.y - BOX_H / 2 - 8 } : { x: b.x - BOX_W / 2 - 8, y: b.y };
            const d = vertical
              ? `M${start.x},${start.y} V${(start.y + end.y) / 2} H${end.x} V${end.y}`
              : `M${start.x},${start.y} H${(start.x + end.x) / 2} V${end.y} H${end.x}`;
            return (
              <g key={i}>
                <motion.path
                  d={d} fill="none" stroke="var(--ink-400)" strokeWidth={1.5} markerEnd="url(#sd-flow-arrow)"
                  initial={reduce ? false : { pathLength: 0 }}
                  animate={inView ? { pathLength: 1 } : { pathLength: 0 }}
                  transition={{ duration: 0.5, delay: 0.2 + i * 0.12, ease: [0.22, 1, 0.36, 1] }}
                />
                {e.label && (
                  <text x={(start.x + end.x) / 2 + 8} y={(start.y + end.y) / 2 - 4} fontSize={10} fontWeight={700} fill="var(--accent-700)">{e.label}</text>
                )}
              </g>
            );
          })}
          {nodes.map((n, i) => {
            const p = byId.get(n)!;
            const kind = n.kind ?? "process";
            const pill = kind === "start" || kind === "end";
            const decision = kind === "decision";
            return (
              <motion.g
                key={n.id}
                initial={reduce ? false : { opacity: 0, scale: 0.85 }}
                animate={inView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.85 }}
                transition={{ duration: 0.4, delay: 0.15 + n.row * 0.18 + i * 0.02, ease: [0.22, 1, 0.36, 1] }}
                style={{ transformOrigin: `${p.x}px ${p.y}px` }}
              >
                {decision ? (
                  <polygon
                    points={`${p.x},${p.y - BOX_H / 2} ${p.x + BOX_W / 2},${p.y} ${p.x},${p.y + BOX_H / 2} ${p.x - BOX_W / 2},${p.y}`}
                    fill="var(--accent-50)" stroke="var(--accent-500)" strokeWidth={2}
                  />
                ) : (
                  <rect
                    x={p.x - BOX_W / 2} y={p.y - BOX_H / 2} width={BOX_W} height={BOX_H}
                    rx={pill ? BOX_H / 2 : 6}
                    fill={pill ? "var(--ink-900)" : "var(--paper)"}
                    stroke={pill ? "var(--ink-900)" : "var(--ink-300)"}
                    strokeWidth={1.5}
                  />
                )}
                <text x={p.x} y={p.y} textAnchor="middle" dominantBaseline="middle" fontSize={11} fontWeight={700} fill={pill ? "var(--accent-500)" : "var(--ink-900)"}>
                  {n.label}
                </text>
              </motion.g>
            );
          })}
        </>
      )}
    </ChartFrame>
  );
}
