import { useEffect, useRef, useState } from "react";
import { Stage, Layer, Rect, Circle, Text, Group, Line, Star } from "react-konva";
import type { KonvaEventObject } from "konva/lib/Node";
import { buildPins, clamp, type PinPos } from "../lib/worldMap";

interface Props {
  regions: string[];
  landmarks: string[];
  pins: Record<string, { x: number; y: number }>;
  selected: string | null;
  onSelect: (name: string | null) => void;
  onPinMove: (name: string, x: number, y: number) => void;
}

export function WorldMap({ regions, landmarks, pins, selected, onSelect, onPinMove }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [size, setSize] = useState({ w: 600, h: 420 });

  // Measure the container so the canvas is responsive. 5:7-ish aspect.
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const update = () => {
      const w = el.clientWidth;
      setSize({ w, h: Math.round(w * 0.62) });
    };
    update();
    const ro = new ResizeObserver(update);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  // Build the pin list: saved positions win, else auto-layout. Pure helper so
  // the layout math has a runnable self-check (see src/lib/worldMap.ts).
  const pinList: PinPos[] = buildPins(regions, landmarks, pins);

  const { w, h } = size;

  return (
    <div ref={containerRef} className="w-full">
      <Stage
        width={w}
        height={h}
        onClick={(e: KonvaEventObject<MouseEvent>) => {
          // Click on empty canvas deselects.
          if (e.target === e.target.getStage()) onSelect(null);
        }}
        className="rounded-xl border border-[var(--color-border-glass)]"
      >
        <Layer>
          {/* Parchment-style chart background: deep navy with a faint gold grid. */}
          <Rect x={0} y={0} width={w} height={h} fill="#0d1424" />
          {/* Faint grid lines */}
          {Array.from({ length: 9 }, (_, i) => {
            const gx = (i + 1) * (w / 10);
            const gy = (i + 1) * (h / 10);
            return (
              <Group key={`grid-${i}`}>
                <Line points={[gx, 0, gx, h]} stroke="#d4af37" opacity={0.05} />
                <Line points={[0, gy, w, gy]} stroke="#d4af37" opacity={0.05} />
              </Group>
            );
          })}
          {/* Vignette frame */}
          <Rect
            x={0}
            y={0}
            width={w}
            height={h}
            stroke="#d4af37"
            strokeWidth={2}
            opacity={0.3}
            listening={false}
            cornerRadius={6}
          />
          {/* Compass rose (top-right) */}
          <Group x={w - 36} y={32} listening={false}>
            <Circle radius={14} stroke="#d4af37" opacity={0.4} />
            <Line points={[0, -14, 0, 14]} stroke="#d4af37" opacity={0.5} />
            <Line points={[-14, 0, 14, 0]} stroke="#d4af37" opacity={0.5} />
            <Text text="N" x={-4} y={-26} fontSize={9} fill="#d4af37" />
          </Group>
        </Layer>

        <Layer>
          {pinList.map((pin) => {
            const px = pin.x * w;
            const py = pin.y * h;
            const isRegion = pin.kind === "region";
            const isSelected = pin.name === selected;
            return (
              <Group
                key={`${pin.kind}-${pin.name}`}
                x={px}
                y={py}
                draggable
                onClick={(e) => {
                  e.cancelBubble = true;
                  onSelect(pin.name);
                }}
                onTap={(e) => {
                  e.cancelBubble = true;
                  onSelect(pin.name);
                }}
                onDragEnd={(e) => {
                  // ponytail: record the clamped normalized position; the React
                  // re-render repositions the node, so no manual snap-back here
                  // (the closure `pin` would be stale and snap it to the old spot).
                  onPinMove(pin.name, clamp(e.target.x() / w), clamp(e.target.y() / h));
                }}
              >
                {isRegion ? (
                  <>
                    <Circle
                      radius={isSelected ? 11 : 8}
                      fill="#d4af37"
                      stroke={isSelected ? "#fff" : "#0a0e1a"}
                      strokeWidth={isSelected ? 2 : 1}
                      shadowColor="#d4af37"
                      shadowBlur={isSelected ? 16 : 6}
                      shadowOpacity={0.6}
                    />
                    <Circle radius={3} fill="#0a0e1a" />
                  </>
                ) : (
                  <Star
                    numPoints={5}
                    innerRadius={4}
                    outerRadius={isSelected ? 9 : 7}
                    fill="#8b9bb4"
                    stroke={isSelected ? "#d4af37" : "#0a0e1a"}
                    strokeWidth={isSelected ? 2 : 1}
                  />
                )}
                <Text
                  text={pin.name}
                  x={-60}
                  y={isRegion ? 12 : 10}
                  width={120}
                  align="center"
                  fontSize={isRegion ? 11 : 10}
                  fontStyle={isRegion ? "bold" : "normal"}
                  fill={isSelected ? "#d4af37" : "#e8e0d0"}
                  stroke="#0a0e1a"
                  strokeWidth={3}
                  // ponytail: paint fill over stroke so the label gets a dark
                  // outline and reads over grid lines + other pins.
                  fillAfterStrokeEnabled
                  listening={false}
                />
              </Group>
            );
          })}
        </Layer>
      </Stage>
    </div>
  );
}