"use client";

import { useId } from "react";

export interface GridPoint {
  x: number;
  y: number;
  label?: string;
  tone?: "solid" | "target" | "wrong" | "muted";
}

export interface GridSegment {
  from: { x: number; y: number };
  to: { x: number; y: number };
}

export interface GridArrow {
  from: { x: number; y: number };
  to: { x: number; y: number };
  dashed?: boolean;
}

interface CartesianGridProps {
  points?: GridPoint[];
  segments?: GridSegment[];
  arrows?: GridArrow[];
  /** Draws dashed guide lines from this point to the axes. `axis` picks which (default both). */
  highlight?: { x: number; y: number; axis?: "x" | "y" | "both" };
  onGridClick?: (x: number, y: number) => void;
}

const MIN = -10;
const MAX = 10;
const UNIT = 20;
const MARGIN = 20;
const SIZE = MARGIN * 2 + (MAX - MIN) * UNIT; // 440

const sx = (x: number) => MARGIN + (x - MIN) * UNIT;
const sy = (y: number) => MARGIN + (MAX - y) * UNIT;

const toneColor: Record<NonNullable<GridPoint["tone"]>, string> = {
  solid: "var(--unit-7)",
  target: "var(--correct)",
  wrong: "var(--incorrect)",
  muted: "var(--muted)",
};

export function CartesianGrid({
  points = [],
  segments = [],
  arrows = [],
  highlight,
  onGridClick,
}: CartesianGridProps) {
  const arrowHeadId = useId();
  const axisArrowId = useId();

  const ticks: number[] = [];
  for (let v = MIN; v <= MAX; v++) ticks.push(v);
  const labelTicks = ticks.filter((v) => v !== 0 && v % 2 === 0);

  function handleClick(e: React.MouseEvent<SVGSVGElement>) {
    if (!onGridClick) return;
    const rect = e.currentTarget.getBoundingClientRect();
    const px = ((e.clientX - rect.left) / rect.width) * SIZE;
    const py = ((e.clientY - rect.top) / rect.height) * SIZE;
    const x = Math.round((px - MARGIN) / UNIT + MIN);
    const y = Math.round(MAX - (py - MARGIN) / UNIT);
    if (x < MIN || x > MAX || y < MIN || y > MAX) return;
    onGridClick(x, y);
  }

  return (
    <svg
      viewBox={`0 0 ${SIZE} ${SIZE}`}
      className={`h-auto w-full max-w-md ${onGridClick ? "cursor-crosshair" : ""}`}
      onClick={handleClick}
      role="img"
      aria-label="Cartesian coordinate grid"
    >
      <defs>
        <marker id={arrowHeadId} markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
          <path d="M0 0 L8 4 L0 8 z" fill="var(--unit-7-dark)" />
        </marker>
        <marker id={axisArrowId} markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">
          <path d="M0 0 L9 4.5 L0 9 z" fill="var(--foreground)" />
        </marker>
      </defs>

      {/* Light gridlines */}
      {ticks.map((v) => (
        <g key={`grid-${v}`}>
          <line x1={sx(v)} y1={sy(MIN)} x2={sx(v)} y2={sy(MAX)} stroke="var(--border)" strokeWidth={1} />
          <line x1={sx(MIN)} y1={sy(v)} x2={sx(MAX)} y2={sy(v)} stroke="var(--border)" strokeWidth={1} />
        </g>
      ))}

      {/* Axes */}
      <line x1={12} y1={sy(0)} x2={SIZE - 8} y2={sy(0)} stroke="var(--foreground)" strokeWidth={2} markerEnd={`url(#${axisArrowId})`} />
      <line x1={sx(0)} y1={SIZE - 8} x2={sx(0)} y2={12} stroke="var(--foreground)" strokeWidth={2} markerEnd={`url(#${axisArrowId})`} />
      <text x={SIZE - 12} y={sy(0) - 8} fontSize={14} fontWeight={700} fill="var(--foreground)" textAnchor="end">x</text>
      <text x={sx(0) + 10} y={18} fontSize={14} fontWeight={700} fill="var(--foreground)">y</text>

      {/* Axis labels */}
      {labelTicks.map((v) => (
        <text key={`xl-${v}`} x={sx(v)} y={sy(0) + 15} fontSize={10} fill="var(--muted)" textAnchor="middle">
          {v}
        </text>
      ))}
      {labelTicks.map((v) => (
        <text key={`yl-${v}`} x={sx(0) - 7} y={sy(v) + 3.5} fontSize={10} fill="var(--muted)" textAnchor="end">
          {v}
        </text>
      ))}
      <text x={sx(0) - 7} y={sy(0) + 15} fontSize={10} fill="var(--muted)" textAnchor="end">0</text>

      {/* Guide lines */}
      {highlight && (
        <g>
          {(highlight.axis ?? "both") !== "y" && (
            <line x1={sx(highlight.x)} y1={sy(highlight.y)} x2={sx(highlight.x)} y2={sy(0)} stroke="var(--unit-7)" strokeWidth={1.5} strokeDasharray="4 3" opacity={0.8} />
          )}
          {(highlight.axis ?? "both") !== "x" && (
            <line x1={sx(highlight.x)} y1={sy(highlight.y)} x2={sx(0)} y2={sy(highlight.y)} stroke="var(--unit-7)" strokeWidth={1.5} strokeDasharray="4 3" opacity={0.8} />
          )}
        </g>
      )}

      {/* Segments */}
      {segments.map((s, i) => (
        <line
          key={`seg-${i}`}
          x1={sx(s.from.x)}
          y1={sy(s.from.y)}
          x2={sx(s.to.x)}
          y2={sy(s.to.y)}
          stroke="var(--unit-7)"
          strokeWidth={2.5}
          strokeLinecap="round"
        />
      ))}

      {/* Movement arrows */}
      {arrows.map((a, i) => (
        <line
          key={`arr-${i}`}
          x1={sx(a.from.x)}
          y1={sy(a.from.y)}
          x2={sx(a.to.x)}
          y2={sy(a.to.y)}
          stroke="var(--unit-7-dark)"
          strokeWidth={2.5}
          strokeLinecap="round"
          strokeDasharray={a.dashed ? "5 4" : undefined}
          markerEnd={`url(#${arrowHeadId})`}
        />
      ))}

      {/* Points */}
      {points.map((p, i) => {
        const color = toneColor[p.tone ?? "solid"];
        return (
          <g key={`pt-${i}`}>
            <circle cx={sx(p.x)} cy={sy(p.y)} r={5} fill={color} stroke="white" strokeWidth={1.5} />
            {p.label && (
              <text
                x={sx(p.x) + 8}
                y={sy(p.y) - 8}
                fontSize={12}
                fontWeight={700}
                fill={color}
              >
                {p.label}
              </text>
            )}
          </g>
        );
      })}
    </svg>
  );
}
