import { assertExists } from '@blockeditor/global/utils';
import {} from '../types.js';
import { matchFlavours } from './model.js';
import { DropFlags, getClosestBlockElementByElement, getDropRectByPoint, getModelByBlockComponent, getRectByBlockElement, } from './query.js';
import { Rect } from './rect.js';
/**
 * Calculates the drop target.
 */
export function calcDropTarget(point, model, element, draggingElements = [], scale = 1, flavour = null // for block-hub
) {
    const schema = model.page.getSchemaByFlavour('affine:database');
    assertExists(schema);
    const children = schema.model.children ?? [];
    let shouldAppendToDatabase = true;
    if (children.length) {
        if (draggingElements.length) {
            shouldAppendToDatabase = draggingElements
                .map(getModelByBlockComponent)
                .every(m => children.includes(m.flavour));
        }
        else if (flavour) {
            shouldAppendToDatabase = children.includes(flavour);
        }
    }
    if (!shouldAppendToDatabase && !matchFlavours(model, ['affine:database'])) {
        const databaseBlockElement = element.closest('affine-database');
        if (databaseBlockElement) {
            element = databaseBlockElement;
            model = getModelByBlockComponent(element);
        }
    }
    let type = 'none';
    const height = 3 * scale;
    const { rect: domRect, flag } = getDropRectByPoint(point, model, element);
    if (flag === DropFlags.EmptyDatabase) {
        // empty database
        const rect = Rect.fromDOMRect(domRect);
        rect.top -= height / 2;
        rect.height = height;
        type = 'database';
        return {
            type,
            rect,
            modelState: {
                model,
                rect: domRect,
                element: element,
            },
        };
    }
    else if (flag === DropFlags.Database) {
        // not empty database
        const distanceToTop = Math.abs(domRect.top - point.y);
        const distanceToBottom = Math.abs(domRect.bottom - point.y);
        const before = distanceToTop < distanceToBottom;
        type = before ? 'before' : 'after';
        return {
            type,
            rect: Rect.fromLWTH(domRect.left, domRect.width, (before ? domRect.top - 1 : domRect.bottom) - height / 2, height),
            modelState: {
                model,
                rect: domRect,
                element: element,
            },
        };
    }
    const distanceToTop = Math.abs(domRect.top - point.y);
    const distanceToBottom = Math.abs(domRect.bottom - point.y);
    const before = distanceToTop < distanceToBottom;
    type = before ? 'before' : 'after';
    let offsetY = 4;
    if (type === 'before') {
        // before
        let prev;
        let prevRect;
        prev = element.previousElementSibling;
        if (prev) {
            if (draggingElements.length &&
                prev === draggingElements[draggingElements.length - 1]) {
                type = 'none';
            }
            else {
                prevRect = getRectByBlockElement(prev);
            }
        }
        else {
            prev = element.parentElement?.previousElementSibling;
            if (prev) {
                prevRect = prev.getBoundingClientRect();
            }
        }
        if (prevRect) {
            offsetY = (domRect.top - prevRect.bottom) / 2;
        }
    }
    else {
        // after
        let next;
        let nextRect;
        next = element.nextElementSibling;
        if (next) {
            if (draggingElements.length && next === draggingElements[0]) {
                type = 'none';
                next = null;
            }
        }
        else {
            next = getClosestBlockElementByElement(element.parentElement)
                ?.nextElementSibling;
        }
        if (next) {
            nextRect = getRectByBlockElement(next);
            offsetY = (nextRect.top - domRect.bottom) / 2;
        }
    }
    if (type === 'none')
        return null;
    let top = domRect.top;
    if (type === 'before') {
        top -= offsetY;
    }
    else {
        top += domRect.height + offsetY;
    }
    return {
        type,
        rect: Rect.fromLWTH(domRect.left, domRect.width, top - height / 2, height),
        modelState: {
            model,
            rect: domRect,
            element: element,
        },
    };
}
//# sourceMappingURL=drag-and-drop.js.map