// #region Imports
import { getRectCenter, isPointInsideRect } from './PositionUtils';
// #endregion
// #region Point-Based Collision
/**
 * Find element at a specific point.
 *
 * @param point - Point to check.
 * @param elements - Elements to check against.
 * @returns Element at point or null.
 *
 * @public
 */
export function getElementAtPoint(point, elements) {
    for (const element of elements) {
        const rect = element.getBoundingClientRect();
        if (isPointInsideRect(point, rect)) {
            return element;
        }
    }
    return null;
}
/**
 * Find all elements at a specific point.
 *
 * @param point - Point to check.
 * @param elements - Elements to check against.
 * @returns Array of elements at point.
 *
 * @public
 */
export function getAllElementsAtPoint(point, elements) {
    return elements.filter((element) => {
        const rect = element.getBoundingClientRect();
        return isPointInsideRect(point, rect);
    });
}
// #endregion
// #region Distance-Based Collision
/**
 * Find nearest element to a point.
 *
 * @param point - Reference point.
 * @param elements - Elements to check.
 * @returns Collision result or null.
 *
 * @public
 */
export function getNearestElement(point, elements) {
    let nearest = null;
    let minDistance = Infinity;
    elements.forEach((element, index) => {
        const rect = element.getBoundingClientRect();
        const center = getRectCenter(rect);
        const dx = center.x - point.x;
        const dy = center.y - point.y;
        const distance = Math.sqrt((dx * dx) + (dy * dy));
        if (distance < minDistance) {
            minDistance = distance;
            nearest = { element,
                distance,
                index };
        }
    });
    return nearest;
}
/**
 * Get elements sorted by distance from a point.
 *
 * @param point - Reference point.
 * @param elements - Elements to check.
 * @returns Array of collision results sorted by distance.
 *
 * @public
 */
export function getElementsByDistance(point, elements) {
    return elements
        .map((element, index) => {
        const rect = element.getBoundingClientRect();
        const center = getRectCenter(rect);
        const dx = center.x - point.x;
        const dy = center.y - point.y;
        const distance = Math.sqrt((dx * dx) + (dy * dy));
        return { element,
            distance,
            index };
    })
        .sort((a, b) => a.distance - b.distance);
}
// #endregion
// #region List-Specific Collision
/**
 * Find drop index in a vertical list.
 *
 * @param elements - List elements or rects.
 * @param point - Pointer position.
 * @returns Drop index.
 *
 * @public
 */
export function getVerticalDropIndex(elements, point) {
    if (elements.length === 0) {
        return 0;
    }
    for (let i = 0; i < elements.length; i++) {
        const rect = elements[i] instanceof Element
            ? elements[i].getBoundingClientRect()
            : elements[i];
        const midpoint = rect.top + (rect.height / 2);
        if (point.y < midpoint) {
            return i;
        }
    }
    return elements.length;
}
/**
 * Find drop index in a horizontal list.
 *
 * @param elements - List elements or rects.
 * @param point - Pointer position.
 * @returns Drop index.
 *
 * @public
 */
export function getHorizontalDropIndex(elements, point) {
    if (elements.length === 0) {
        return 0;
    }
    for (let i = 0; i < elements.length; i++) {
        const rect = elements[i] instanceof Element
            ? elements[i].getBoundingClientRect()
            : elements[i];
        const midpoint = rect.left + (rect.width / 2);
        if (point.x < midpoint) {
            return i;
        }
    }
    return elements.length;
}
/**
 * Find drop index in a mixed/grid layout.
 *
 * @param elements - List elements or rects.
 * @param point - Pointer position.
 * @returns Drop index.
 *
 * @public
 */
export function getMixedDropIndex(elements, point) {
    if (elements.length === 0) {
        return 0;
    }
    // Convert to HTML elements for getNearestElement
    if (!(elements[0] instanceof Element)) {
        // Can't use getNearestElement with DOMRects directly, fall back to closest center
        let minDistance = Infinity;
        let closestIndex = 0;
        elements.forEach((item, index) => {
            const rect = item;
            const center = getRectCenter(rect);
            const dx = center.x - point.x;
            const dy = center.y - point.y;
            const distance = Math.sqrt((dx * dx) + (dy * dy));
            if (distance < minDistance) {
                minDistance = distance;
                closestIndex = index;
            }
        });
        const rect = elements[closestIndex];
        const center = getRectCenter(rect);
        const dx = point.x - center.x;
        const dy = point.y - center.y;
        if (dy < -rect.height / 4) {
            return closestIndex;
        }
        else if (dy > rect.height / 4) {
            return closestIndex + 1;
        }
        else {
            return dx < 0 ? closestIndex : closestIndex + 1;
        }
    }
    const nearest = getNearestElement(point, elements);
    if (!nearest) {
        return 0;
    }
    const rect = nearest.element.getBoundingClientRect();
    const center = getRectCenter(rect);
    // Determine if we should insert before or after
    const dx = point.x - center.x;
    const dy = point.y - center.y;
    // Use combined heuristic: primarily Y, then X
    if (dy < -rect.height / 4) {
        // Well above: insert before
        return nearest.index;
    }
    else if (dy > rect.height / 4) {
        // Well below: insert after
        return nearest.index + 1;
    }
    else {
        // Around same Y level: use X
        return dx < 0 ? nearest.index : nearest.index + 1;
    }
}
// #endregion
// #region Rect Collision
/**
 * Check if two rects intersect.
 *
 * @param rect1 - First rect.
 * @param rect2 - Second rect.
 * @returns True if rects intersect.
 *
 * @public
 */
export function rectsIntersect(rect1, rect2) {
    return !(rect1.right < rect2.left ||
        rect1.left > rect2.right ||
        rect1.bottom < rect2.top ||
        rect1.top > rect2.bottom);
}
/**
 * Calculate intersection area of two rects.
 *
 * @param rect1 - First rect.
 * @param rect2 - Second rect.
 * @returns Intersection area in pixels².
 *
 * @public
 */
export function getIntersectionArea(rect1, rect2) {
    const left = Math.max(rect1.left, rect2.left);
    const right = Math.min(rect1.right, rect2.right);
    const top = Math.max(rect1.top, rect2.top);
    const bottom = Math.min(rect1.bottom, rect2.bottom);
    if (left >= right || top >= bottom) {
        return 0;
    }
    return (right - left) * (bottom - top);
}
// #endregion
//# sourceMappingURL=CollisionDetection.js.map