import { useState, useEffect, useCallback, useRef } from "react";
import Konva from "konva";
import { useEditorStore } from "@/pages/editor/store/editorStore";
import type { EditorObject } from "@/pages/editor/store/editorStore";

// --- Constants ---

/** Radius (in canvas units, before zoom) within which clicking snaps to / closes on the first vertex. */
const CLOSE_THRESHOLD = 12;

/** Minimum number of vertices required to close a shape. */
const MIN_POINTS = 3;

// --- Types ---

/** A 2-D point in canvas (stage-local) coordinates. */
export type DrawPoint = { x: number; y: number };

/** Reactive state consumed by CustomShapeDrawingLayer for rendering the in-progress polygon. */
export type CustomShapeDrawingState = {
  isActive: boolean;
  points: DrawPoint[];
  previewPoint: DrawPoint | null;
};

const INITIAL_STATE: CustomShapeDrawingState = {
  isActive: false,
  points: [],
  previewPoint: null,
};

// --- Helpers ---

const getCanvasPos = (stage: Konva.Stage): DrawPoint | null => {
  const pos = stage.getPointerPosition();
  if (!pos) return null;
  return {
    x: pos.x / stage.scaleX(),
    y: pos.y / stage.scaleY(),
  };
};

const isNearPoint = (a: DrawPoint, b: DrawPoint, threshold: number): boolean => {
  const dx = a.x - b.x;
  const dy = a.y - b.y;
  return dx * dx + dy * dy <= threshold * threshold;
};

/**
 * Converts absolute canvas points into an EditorObject.
 * The bounding-box top-left becomes (obj.x, obj.y); all points are stored relative to it.
 * width/height reflect the axis-aligned bounding box so the transformer can display correct handles.
 */
const buildCustomShapeObject = (points: DrawPoint[]): EditorObject => {
  const xs = points.map((p) => p.x);
  const ys = points.map((p) => p.y);
  const minX = Math.min(...xs);
  const minY = Math.min(...ys);
  const maxX = Math.max(...xs);
  const maxY = Math.max(...ys);

  // Flat [x1-minX, y1-minY, x2-minX, y2-minY, …] — Konva.Line.points format
  const normalizedPoints = points.flatMap((p) => [p.x - minX, p.y - minY]);

  return {
    id: `custom-shape-${Date.now()}`,
    type: "custom-shape",
    x: minX,
    y: minY,
    width: maxX - minX,
    height: maxY - minY,
    points: normalizedPoints,
    closed: true,
    fill: "#3b82f6",
    fillType: "solid",
    stroke: "#1e40af",
    strokeWidth: 2,
    opacity: 100,
    rotation: 0,
  };
};

// --- Hook ---

/**
 * Manages the click-by-click custom polygon drawing state machine.
 *
 * Usage in EditorCanvas:
 *   - Attach handleStageClick   → Stage onClick
 *   - Attach handleStageMouseMove → Stage onMouseMove
 *   - Render <CustomShapeDrawingLayer drawingState={drawingState} />
 *
 * The hook integrates with the Zustand editor store (addObject, undo history, tool switch)
 * and cleans up its own keyboard listener on unmount / tool change.
 */
export const useCustomShapeDrawing = () => {
  // Use a ref for the mutable points array so event callbacks always see the latest
  // value without needing to be recreated on every state update.
  const pointsRef = useRef<DrawPoint[]>([]);

  const [drawingState, setDrawingState] = useState<CustomShapeDrawingState>(INITIAL_STATE);

  const { tool, addObject, setSelectedObjectId, setTool } = useEditorStore();

  const reset = useCallback(() => {
    pointsRef.current = [];
    setDrawingState(INITIAL_STATE);
  }, []);

  // Cancel drawing when user switches away from the custom-shape tool
  useEffect(() => {
    if (tool !== "custom-shape") {
      reset();
    }
  }, [tool, reset]);

  // Escape key cancels in-progress drawing
  useEffect(() => {
    if (tool !== "custom-shape") return;

    const handleKeyDown = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement;
      if (
        target.tagName === "INPUT" ||
        target.tagName === "TEXTAREA" ||
        target.isContentEditable
      ) {
        return;
      }

      if (e.key === "Escape") {
        e.preventDefault();
        reset();
        setTool("select");
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [tool, reset, setTool]);

  /** Finalise the polygon, persist it to the store, and switch to select tool. */
  const commitShape = useCallback(() => {
    const points = pointsRef.current;
    if (points.length < MIN_POINTS) return;

    const obj = buildCustomShapeObject(points);
    useEditorStore.getState().commitObjectHistoryBeforeChange();
    addObject(obj);
    setSelectedObjectId(obj.id);
    setTool("select");
    reset();
  }, [addObject, setSelectedObjectId, setTool, reset]);

  /**
   * Stage click handler.
   *
   * Only acts when tool === "custom-shape" and the click target is the Stage itself
   * (not an existing shape). Uses MouseEvent.detail to distinguish single vs double clicks:
   * - detail === 1 → single click → add vertex or close shape if near first vertex
   * - detail >= 2  → second click of a double-click → close the shape immediately
   */
  const handleStageClick = useCallback(
    (e: Konva.KonvaEventObject<MouseEvent>) => {
      if (tool !== "custom-shape") return;
      // Only act on bare-stage clicks; ignore clicks that land on existing objects
      const stage = e.target.getStage();
      if (!stage || e.target !== stage) return;

      const pos = getCanvasPos(stage);
      if (!pos) return;

      // Double-click (detail >= 2): close the shape without adding another vertex
      if (e.evt.detail >= 2) {
        if (pointsRef.current.length >= MIN_POINTS) {
          commitShape();
        }
        return;
      }

      const points = pointsRef.current;

      // Snap-to-close: if cursor is within threshold of the first vertex, close the shape
      if (
        points.length >= MIN_POINTS &&
        isNearPoint(pos, points[0], CLOSE_THRESHOLD)
      ) {
        commitShape();
        return;
      }

      // Add vertex
      pointsRef.current = [...points, pos];
      setDrawingState({
        isActive: true,
        points: pointsRef.current,
        previewPoint: pos,
      });
    },
    [tool, commitShape],
  );

  /** Updates the live preview segment as the mouse moves across the canvas. */
  const handleStageMouseMove = useCallback(
    (e: Konva.KonvaEventObject<MouseEvent>) => {
      if (tool !== "custom-shape" || !drawingState.isActive) return;

      const stage = e.target.getStage();
      if (!stage) return;

      const pos = getCanvasPos(stage);
      if (!pos) return;

      setDrawingState((prev) => ({ ...prev, previewPoint: pos }));
    },
    [tool, drawingState.isActive],
  );

  return {
    drawingState,
    handleStageClick,
    handleStageMouseMove,
  };
};
