"use client";

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

export type SeqActor = { id: string; label: string };
export type SeqMessage = { from: string; to: string; label: string; dashed?: boolean };

type SequenceDiagramProps = {
  actors: SeqActor[];
  messages: SeqMessage[];
  width?: number;
  height?: number;
  className?: string;
};

const TOP = 40;
const MSG_GAP = 46;

/** SequenceDiagram — actor boxes + dashed lifelines that draw down; messages are horizontal arrows drawn one after another top→down. */
export function SequenceDiagram({ actors, messages, width = 680, height, className }: SequenceDiagramProps) {
  const h = height ?? TOP + 30 + messages.length * MSG_GAP + 30;
  const pad = 80;
  const lifeX = (i: number) => (actors.length === 1 ? width / 2 : pad + (i / (actors.length - 1)) * (width - pad * 2));
  const idxOf = new Map(actors.map((a, i) => [a.id, i]));

  return (
    <ChartFrame width={width} height={h} label="Diagrama de secuencia" className={className}>
      {({ inView, reduce }) => (
        <>
          <defs>
            <marker id="sd-seq-arrow" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto">
              <path d="M0,0 L7,3 L0,6 Z" fill="var(--ink-700)" />
            </marker>
          </defs>
          {actors.map((a, i) => {
            const x = lifeX(i);
            return (
              <g key={a.id}>
                <motion.line
                  x1={x} x2={x} y1={TOP + 16} y2={h - 20}
                  stroke="var(--ink-300)" strokeWidth={1.5} strokeDasharray="4 4"
                  initial={reduce ? false : { pathLength: 0 }}
                  animate={inView ? { pathLength: 1 } : { pathLength: 0 }}
                  transition={{ duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
                />
                <motion.g
                  initial={reduce ? false : { opacity: 0, y: -8 }}
                  animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: -8 }}
                  transition={{ duration: 0.4, delay: 0.05 + i * 0.06 }}
                >
                  <rect x={x - 56} y={TOP - 16} width={112} height={32} rx={6} fill="var(--ink-900)" />
                  <text x={x} y={TOP} textAnchor="middle" dominantBaseline="middle" fontSize={12} fontWeight={700} fill="var(--accent-500)">{a.label}</text>
                </motion.g>
              </g>
            );
          })}
          {messages.map((m, i) => {
            const x0 = lifeX(idxOf.get(m.from) ?? 0);
            const x1 = lifeX(idxOf.get(m.to) ?? 0);
            const y = TOP + 40 + i * MSG_GAP;
            const dir = x1 >= x0 ? 1 : -1;
            return (
              <motion.g
                key={i}
                initial={reduce ? false : { opacity: 0 }}
                animate={inView ? { opacity: 1 } : { opacity: 0 }}
                transition={{ duration: 0.35, delay: 0.6 + i * 0.28 }}
              >
                <line x1={x0} y1={y} x2={x1 - dir * 8} y2={y} stroke="var(--ink-700)" strokeWidth={1.5} strokeDasharray={m.dashed ? "5 4" : undefined} markerEnd="url(#sd-seq-arrow)" />
                <text x={(x0 + x1) / 2} y={y - 7} textAnchor="middle" fontSize={11} fill="var(--ink-700)">{m.label}</text>
              </motion.g>
            );
          })}
        </>
      )}
    </ChartFrame>
  );
}
