"use client";

import clsx from "clsx";
import { createContext, memo, useContext } from "react";
import { Handle, Position, type Node, type NodeProps } from "@xyflow/react";
import { AlertCircle, AlertTriangle, Copy, Trash2 } from "lucide-react";
import type { FlowIssue, FlowNodeType } from "@/lib/types";
import { NODE_META, outputsOf, summaryOf } from "./node-meta";

export type BuilderNode = Node<Record<string, unknown>, FlowNodeType>;

/** Builder-wide state the nodes read without it being stored in node data. */
export const BuilderContext = createContext<{
  issues: Map<string, FlowIssue[]>;
  trigger: string | null;
  readOnly: boolean;
  onDuplicate: (id: string) => void;
  onDelete: (id: string) => void;
  /** The step the preview is waiting on. */
  activeNodeId: string | null;
}>({ issues: new Map(), trigger: null, readOnly: false, onDuplicate: () => {}, onDelete: () => {}, activeNodeId: null });

function FlowNodeCardImpl({ id, type, data, selected }: NodeProps<BuilderNode>) {
  const ctx = useContext(BuilderContext);
  const meta = NODE_META[type];
  const outputs = outputsOf(type, data);
  const issues = ctx.issues.get(id) ?? [];
  const errors = issues.filter((i) => i.severity === "error");
  const label = (data.label as string | undefined) || meta.label;
  const single = outputs.length === 1 && outputs[0].id === "next";

  return (
    <div
      className={clsx(
        "group relative w-[260px] rounded-lg border bg-white text-left shadow-sm transition-shadow",
        selected ? "border-teal shadow-md ring-2 ring-teal/25" : errors.length ? "border-brick/60" : "border-line",
        ctx.activeNodeId === id && "ring-4 ring-mint/60",
      )}
    >
      {ctx.activeNodeId === id && <span className="absolute -top-6 left-0 rounded bg-mint px-1.5 py-0.5 text-[11px] font-semibold text-ink">Preview is here</span>}
      {type !== "start" && <Handle type="target" position={Position.Left} id="in" className="!size-3 !border-2 !border-white !bg-ink" aria-label="Input" />}
      <div className={clsx("flex items-center gap-2 rounded-t-lg px-3 py-2 [&_svg]:size-4", meta.accent)}>
        {meta.icon}
        <span className="min-w-0 flex-1 truncate text-[13px] font-semibold">{label}</span>
        {issues.length > 0 && (
          <span title={issues.map((i) => i.message).join("\n")} className={clsx("shrink-0", errors.length ? "text-brick" : "text-amber")}>
            {errors.length ? <AlertCircle /> : <AlertTriangle />}
          </span>
        )}
        {!ctx.readOnly && type !== "start" && (
          <span className="nodrag flex shrink-0 gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
            <button type="button" onClick={() => ctx.onDuplicate(id)} className="rounded p-0.5 hover:bg-black/10" aria-label={`Duplicate ${label}`} title="Duplicate">
              <Copy className="!size-3.5" />
            </button>
            <button type="button" onClick={() => ctx.onDelete(id)} className="rounded p-0.5 hover:bg-black/10" aria-label={`Delete ${label}`} title="Delete">
              <Trash2 className="!size-3.5" />
            </button>
          </span>
        )}
      </div>
      <div className="px-3 py-2.5">
        {label !== meta.label && <p className="mb-0.5 text-[11px] font-medium uppercase tracking-wide text-muted">{meta.label}</p>}
        <p className="line-clamp-3 break-words text-[13px] leading-snug text-text">{summaryOf(type, data, ctx.trigger)}</p>
      </div>
      {single ? (
        <Handle type="source" position={Position.Right} id="next" className="!size-3 !border-2 !border-white !bg-teal" aria-label="Next" />
      ) : (
        outputs.length > 0 && (
          <ul className="border-t border-line py-1">
            {outputs.map((o) => (
              <li key={o.id} className="relative flex h-7 items-center justify-end pl-3 pr-4 text-[12.5px]">
                <span className={clsx("truncate", o.muted ? "text-muted" : "font-medium text-ink")}>{o.label}</span>
                <Handle
                  type="source"
                  position={Position.Right}
                  id={o.id}
                  className={clsx("!size-3 !border-2 !border-white", o.muted ? "!bg-muted" : o.id === "false" ? "!bg-brick" : "!bg-teal")}
                  aria-label={o.label}
                />
              </li>
            ))}
          </ul>
        )
      )}
    </div>
  );
}

export const FlowNodeCard = memo(FlowNodeCardImpl);
