import type { PointerEvent as ReactPointerEvent } from "react";

import type { CurvePoint } from "@/types/profile";
import { sampleCurve } from "@/utils/curveMath";

interface CurveEditorProps {
  points: CurvePoint[];
  onChange: (points: CurvePoint[]) => void;
}

const SIZE = 220;
const PADDING = 18;
const PLOT_SIZE = SIZE - PADDING * 2;

function pointToSvg(point: CurvePoint): { x: number; y: number } {
  return { x: PADDING + point.x * PLOT_SIZE, y: PADDING + (1 - point.y) * PLOT_SIZE };
}

function svgToPoint(event: ReactPointerEvent<SVGSVGElement | SVGCircleElement>): CurvePoint {
  const svg = event.currentTarget instanceof SVGSVGElement
    ? event.currentTarget
    : event.currentTarget.ownerSVGElement;
  if (!svg) return { x: 0, y: 0 };
  const bounds = svg.getBoundingClientRect();
  return {
    x: Math.min(1, Math.max(0, (event.clientX - bounds.left - PADDING) / PLOT_SIZE)),
    y: Math.min(1, Math.max(0, 1 - (event.clientY - bounds.top - PADDING) / PLOT_SIZE)),
  };
}

/** Interactive, dependency-free custom response-curve point editor. */
export function CurveEditor({ points, onChange }: CurveEditorProps) {
  const sorted = [...points].sort((a, b) => a.x - b.x);
  const samples = sampleCurve("custom", sorted);
  const line = samples.map((point) => {
    const svg = pointToSvg(point);
    return `${svg.x},${svg.y}`;
  }).join(" ");

  function addPoint(event: ReactPointerEvent<SVGSVGElement>) {
    if ((event.target as Element).tagName !== "svg") return;
    const point = svgToPoint(event);
    onChange([...sorted, point].sort((a, b) => a.x - b.x));
  }

  function movePoint(index: number, event: ReactPointerEvent<SVGCircleElement>) {
    const next = [...sorted];
    const candidate = svgToPoint(event);
    // Endpoints remain anchored at input 0/1, preventing invalid curves.
    if (index === 0) candidate.x = 0;
    if (index === next.length - 1) candidate.x = 1;
    const lower = index === 0 ? 0 : next[index - 1].x + 0.01;
    const upper = index === next.length - 1 ? 1 : next[index + 1].x - 0.01;
    candidate.x = Math.min(upper, Math.max(lower, candidate.x));
    next[index] = candidate;
    onChange(next);
  }

  return (
    <div>
      <svg
        viewBox={`0 0 ${SIZE} ${SIZE}`}
        className="w-full max-w-[220px] cursor-crosshair rounded-lg border border-border bg-surface-2"
        onPointerDown={addPoint}
        aria-label="Custom response curve editor"
      >
        {[0.25, 0.5, 0.75].map((value) => (
          <g key={value}>
            <line x1={PADDING} x2={SIZE - PADDING} y1={PADDING + value * PLOT_SIZE} y2={PADDING + value * PLOT_SIZE} className="stroke-border" />
            <line y1={PADDING} y2={SIZE - PADDING} x1={PADDING + value * PLOT_SIZE} x2={PADDING + value * PLOT_SIZE} className="stroke-border" />
          </g>
        ))}
        <polyline points={line} fill="none" className="stroke-accent" strokeWidth={2.5} />
        {sorted.map((point, index) => {
          const svg = pointToSvg(point);
          return (
            <circle
              key={`${point.x}-${point.y}-${index}`}
              cx={svg.x}
              cy={svg.y}
              r={5}
              className="cursor-grab fill-accent stroke-surface active:cursor-grabbing"
              strokeWidth={2}
              onPointerDown={(event) => {
                event.stopPropagation();
                event.currentTarget.setPointerCapture(event.pointerId);
              }}
              onPointerMove={(event) => {
                if (event.currentTarget.hasPointerCapture(event.pointerId)) movePoint(index, event);
              }}
            />
          );
        })}
      </svg>
      <p className="mt-1 text-xs text-fg-subtle">Click to add a point; drag points to adjust the curve.</p>
    </div>
  );
}
