import { useCallback } from 'react';
import type { Point, Wall } from '@house-plan-maker/shared';
import { snapPointToGrid } from '../utils/geometry';
import { findNearestWall } from '../utils/wallUtils';

interface UseSnappingOptions {
  readonly snapEnabled: boolean;
  readonly snapGranularity: number;
  readonly walls: readonly Wall[];
}

/** Maximum distance (in meters) to snap to a wall. */
const WALL_SNAP_DISTANCE = 0.3;

interface UseSnappingResult {
  /** Snap a point to the grid. */
  snapToGrid(point: Point): Point;
  /**
   * Snap a point to the nearest wall if close enough.
   * Returns the snapped point and the wall it snapped to.
   */
  snapToWall(point: Point): { snapped: Point; wall: Wall | null; positionAlongWall: number };
  /**
   * Apply all active snapping (grid + wall).
   * Wall snapping takes priority when close enough.
   */
  snapPoint(point: Point): Point;
}

export function useSnapping({
  snapEnabled,
  snapGranularity,
  walls,
}: UseSnappingOptions): UseSnappingResult {
  const snapToGridFn = useCallback(
    (point: Point): Point => {
      if (!snapEnabled) return point;
      return snapPointToGrid(point, snapGranularity);
    },
    [snapEnabled, snapGranularity],
  );

  const snapToWallFn = useCallback(
    (
      point: Point,
    ): { snapped: Point; wall: Wall | null; positionAlongWall: number } => {
      if (!snapEnabled || walls.length === 0) {
        return { snapped: point, wall: null, positionAlongWall: 0 };
      }

      const nearest = findNearestWall(point, walls);
      if (!nearest || nearest.distance > WALL_SNAP_DISTANCE) {
        return { snapped: point, wall: null, positionAlongWall: 0 };
      }

      return {
        snapped: nearest.projected,
        wall: nearest.wall,
        positionAlongWall: nearest.positionAlongWall,
      };
    },
    [snapEnabled, walls],
  );

  const snapPointFn = useCallback(
    (point: Point): Point => {
      if (!snapEnabled) return point;
      // Grid snapping only (wall snapping is used specifically by door/window tools)
      return snapPointToGrid(point, snapGranularity);
    },
    [snapEnabled, snapGranularity],
  );

  return {
    snapToGrid: snapToGridFn,
    snapToWall: snapToWallFn,
    snapPoint: snapPointFn,
  };
}
